1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-12-01 02:44:37 +01:00
actix-extras/src/redis.rs

137 lines
3.8 KiB
Rust
Raw Normal View History

2017-12-29 06:14:04 +01:00
use std::io;
use std::collections::VecDeque;
2018-01-22 09:40:50 +01:00
use actix::prelude::*;
use backoff::ExponentialBackoff;
use backoff::backoff::Backoff;
2017-12-29 06:14:04 +01:00
use futures::Future;
use futures::unsync::oneshot;
2018-01-22 09:40:50 +01:00
use tokio_io::AsyncRead;
2017-12-29 06:14:04 +01:00
use tokio_core::net::TcpStream;
use redis_async::{resp, error};
2018-01-22 09:40:50 +01:00
use connect::TcpConnector;
2017-12-29 06:14:04 +01:00
#[derive(Fail, Debug)]
pub enum Error {
2018-01-22 09:40:50 +01:00
#[fail(display="Redis error {}", _0)]
2017-12-29 06:14:04 +01:00
Redis(error::Error),
2018-01-22 09:40:50 +01:00
/// Receiving message during reconnecting
#[fail(display="Redis: Not connected")]
NotConnected,
/// Cancel all waters when connection get dropped
#[fail(display="Redis: Disconnected")]
Disconnected,
2017-12-29 06:14:04 +01:00
}
unsafe impl Send for Error {}
unsafe impl Sync for Error {}
2018-01-05 23:52:07 +01:00
impl From<error::Error> for Error {
fn from(err: error::Error) -> Error {
Error::Redis(err)
2017-12-29 06:14:04 +01:00
}
}
pub struct Command(pub resp::RespValue);
impl ResponseType for Command {
type Item = resp::RespValue;
type Error = Error;
}
/// Redis comminucation actor
pub struct RedisActor {
2018-01-22 09:40:50 +01:00
addr: String,
backoff: ExponentialBackoff,
cell: Option<FramedCell<RedisActor>>,
2017-12-29 06:14:04 +01:00
queue: VecDeque<oneshot::Sender<Result<resp::RespValue, Error>>>,
}
impl RedisActor {
2018-01-22 09:40:50 +01:00
pub fn start<S: Into<String>>(addr: S) -> Address<RedisActor> {
let addr = addr.into();
Supervisor::start(|_| {
RedisActor { addr: addr,
cell: None,
backoff: ExponentialBackoff::default(),
queue: VecDeque::new() }
}).0
2017-12-29 06:14:04 +01:00
}
}
impl Actor for RedisActor {
2018-01-22 09:40:50 +01:00
type Context = Context<Self>;
fn started(&mut self, ctx: &mut Context<Self>) {
TcpConnector::new(self.addr.as_str())
.into_actor(self)
.map(|stream, act, ctx| {
info!("Connected to redis server: {}", act.addr);
act.backoff.reset();
2018-01-22 10:05:50 +01:00
act.cell = Some(act.add_framed(stream.framed(resp::RespCodec), ctx));
2018-01-22 09:40:50 +01:00
})
.map_err(|err, act, ctx| {
error!("Can not connect to redis server: {}", err);
debug!("{:?}", err);
if let Some(timeout) = act.backoff.next_backoff() {
// delay re-connect, drop all messages during this period
ctx.run_later(timeout, |_, ctx| {
ctx.stop()
});
} else {
ctx.stop();
}
})
.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-29 06:14:04 +01:00
}
impl FramedActor for RedisActor {
type Io = TcpStream;
2018-01-05 23:52:07 +01:00
type Codec = resp::RespCodec;
2017-12-29 06:14:04 +01:00
2018-01-22 09:40:50 +01:00
fn closed(&mut self, error: Option<io::Error>, _: &mut Self::Context) {
if let Some(err) = error {
warn!("Redis connection dropped: {} error: {}", self.addr, err);
} else {
warn!("Redis connection dropped: {}", self.addr);
}
}
2018-01-05 23:52:07 +01:00
fn handle(&mut self, msg: Result<resp::RespValue, error::Error>, _ctx: &mut Self::Context) {
2017-12-29 06:14:04 +01:00
if let Some(tx) = self.queue.pop_front() {
2018-01-05 23:52:07 +01:00
let _ = tx.send(msg.map_err(|e| e.into()));
2017-12-29 06:14:04 +01:00
}
}
}
impl Handler<Command> for RedisActor {
2018-01-05 23:52:07 +01:00
type Result = ResponseFuture<Self, Command>;
2018-01-22 09:40:50 +01:00
fn handle(&mut self, msg: Command, _: &mut Self::Context) -> Self::Result {
2017-12-29 06:14:04 +01:00
let (tx, rx) = oneshot::channel();
2018-01-22 09:40:50 +01:00
if let Some(ref mut cell) = self.cell {
self.queue.push_back(tx);
cell.send(msg.0);
} else {
let _ = tx.send(Err(Error::NotConnected));
}
2017-12-29 06:14:04 +01:00
2018-01-05 23:52:07 +01:00
Box::new(
2018-01-22 09:40:50 +01:00
rx.map_err(|_| Error::Disconnected)
2017-12-29 06:14:04 +01:00
.and_then(|res| res)
.actfuture())
}
}