1
0
mirror of https://github.com/actix/actix-extras.git synced 2025-02-23 19:03:03 +01:00

151 lines
4.6 KiB
Rust
Raw Normal View History

2017-12-28 21:14:04 -08:00
use std::collections::VecDeque;
2018-05-08 10:12:57 -07:00
use std::io;
2017-12-28 21:14:04 -08:00
2018-07-20 14:53:56 -07:00
use actix::actors::resolver::{Connect, Resolver};
2018-05-08 10:12:57 -07:00
use actix::prelude::*;
2019-12-15 23:46:03 +06:00
use actix_utils::oneshot;
2018-01-22 00:40:50 -08:00
use backoff::backoff::Backoff;
2018-05-08 10:12:57 -07:00
use backoff::ExponentialBackoff;
2020-05-21 17:17:56 +09:00
use futures_util::FutureExt;
2020-07-14 19:20:42 +09:00
use log::{error, info, warn};
2018-01-22 10:42:13 -08:00
use redis_async::error::Error as RespError;
use redis_async::resp::{RespCodec, RespValue};
2019-12-15 23:46:03 +06:00
use tokio::io::{split, WriteHalf};
use tokio::net::TcpStream;
use tokio_util::codec::FramedRead;
2017-12-28 21:14:04 -08:00
2019-03-29 11:31:48 -07:00
use crate::Error;
2017-12-28 21:14:04 -08:00
2018-02-17 21:37:30 +03:00
/// Command for send data to Redis
2018-02-15 16:53:05 -08:00
#[derive(Debug)]
2018-01-22 10:42:13 -08:00
pub struct Command(pub RespValue);
2017-12-28 21:14:04 -08:00
2018-02-15 16:53:05 -08:00
impl Message for Command {
type Result = Result<RespValue, Error>;
}
2017-12-28 21:14:04 -08:00
/// Redis comminucation actor
pub struct RedisActor {
2018-01-22 00:40:50 -08:00
addr: String,
backoff: ExponentialBackoff,
cell: Option<actix::io::FramedWrite<RespValue, WriteHalf<TcpStream>, RespCodec>>,
2018-01-22 10:42:13 -08:00
queue: VecDeque<oneshot::Sender<Result<RespValue, Error>>>,
2017-12-28 21:14:04 -08:00
}
impl RedisActor {
2018-02-17 21:37:30 +03:00
/// Start new `Supervisor` with `RedisActor`.
2018-07-20 14:53:56 -07:00
pub fn start<S: Into<String>>(addr: S) -> Addr<RedisActor> {
2018-01-22 00:40:50 -08:00
let addr = addr.into();
2020-11-23 10:37:56 +00:00
let backoff = ExponentialBackoff {
max_elapsed_time: None,
..Default::default()
};
2018-05-08 10:12:57 -07:00
Supervisor::start(|_| RedisActor {
2018-07-20 14:53:56 -07:00
addr,
2018-05-08 10:12:57 -07:00
cell: None,
2019-09-30 09:19:24 +09:00
backoff,
2018-05-08 10:12:57 -07:00
queue: VecDeque::new(),
2018-01-22 10:27:59 -08:00
})
2017-12-28 21:14:04 -08:00
}
}
impl Actor for RedisActor {
2018-01-22 00:40:50 -08:00
type Context = Context<Self>;
fn started(&mut self, ctx: &mut Context<Self>) {
2018-07-20 14:53:56 -07:00
Resolver::from_registry()
2018-05-08 10:12:57 -07:00
.send(Connect::host(self.addr.as_str()))
2018-01-22 00:40:50 -08:00
.into_actor(self)
2018-02-15 16:53:05 -08:00
.map(|res, act, ctx| match res {
2019-12-15 23:46:03 +06:00
Ok(res) => match res {
Ok(stream) => {
info!("Connected to redis server: {}", act.addr);
2018-02-15 16:53:05 -08:00
2019-12-15 23:46:03 +06:00
let (r, w) = split(stream);
2018-02-15 16:53:05 -08:00
2019-12-15 23:46:03 +06:00
// configure write side of the connection
let framed = actix::io::FramedWrite::new(w, RespCodec, ctx);
act.cell = Some(framed);
2018-02-15 16:53:05 -08:00
2019-12-15 23:46:03 +06:00
// read side of the connection
ctx.add_stream(FramedRead::new(r, RespCodec));
2018-02-15 16:53:05 -08:00
2019-12-15 23:46:03 +06:00
act.backoff.reset();
}
Err(err) => {
error!("Can not connect to redis server: {}", err);
// re-connect with backoff time.
// we stop current context, supervisor will restart it.
if let Some(timeout) = act.backoff.next_backoff() {
ctx.run_later(timeout, |_, ctx| ctx.stop());
}
}
},
2018-02-15 16:53:05 -08:00
Err(err) => {
error!("Can not connect to redis server: {}", err);
// re-connect with backoff time.
2018-02-17 10:59:21 +03:00
// we stop current context, supervisor will restart it.
2018-02-15 16:53:05 -08:00
if let Some(timeout) = act.backoff.next_backoff() {
ctx.run_later(timeout, |_, ctx| ctx.stop());
}
}
2018-01-22 00:40:50 -08:00
})
.wait(ctx);
}
}
impl Supervised for RedisActor {
fn restarting(&mut self, _: &mut Self::Context) {
self.cell.take();
for tx in self.queue.drain(..) {
let _ = tx.send(Err(Error::Disconnected));
}
}
2017-12-28 21:14:04 -08:00
}
2018-02-15 16:53:05 -08:00
impl actix::io::WriteHandler<io::Error> for RedisActor {
fn error(&mut self, err: io::Error, _: &mut Self::Context) -> Running {
2018-07-20 14:53:56 -07:00
warn!("Redis connection dropped: {} error: {}", self.addr, err);
2018-02-15 16:53:05 -08:00
Running::Stop
}
}
2019-12-15 23:46:03 +06:00
impl StreamHandler<Result<RespValue, RespError>> for RedisActor {
fn handle(&mut self, msg: Result<RespValue, RespError>, ctx: &mut Self::Context) {
match msg {
Err(e) => {
if let Some(tx) = self.queue.pop_front() {
let _ = tx.send(Err(e.into()));
}
ctx.stop();
}
Ok(val) => {
if let Some(tx) = self.queue.pop_front() {
let _ = tx.send(Ok(val));
}
}
2017-12-28 21:14:04 -08:00
}
}
}
impl Handler<Command> for RedisActor {
2019-12-15 23:46:03 +06:00
type Result = ResponseFuture<Result<RespValue, Error>>;
2018-01-05 14:52:07 -08:00
2018-01-22 00:40:50 -08:00
fn handle(&mut self, msg: Command, _: &mut Self::Context) -> Self::Result {
2017-12-28 21:14:04 -08:00
let (tx, rx) = oneshot::channel();
2018-01-22 00:40:50 -08:00
if let Some(ref mut cell) = self.cell {
self.queue.push_back(tx);
2018-02-15 16:53:05 -08:00
cell.write(msg.0);
2018-01-22 00:40:50 -08:00
} else {
let _ = tx.send(Err(Error::NotConnected));
}
2017-12-28 21:14:04 -08:00
2019-12-20 22:09:08 +06:00
Box::pin(rx.map(|res| match res {
2019-12-15 23:46:03 +06:00
Ok(res) => res,
Err(_) => Err(Error::Disconnected),
}))
2017-12-28 21:14:04 -08:00
}
}