r2d2_redis/
lib.rs

1//! Redis support for the `r2d2` connection pool.
2#![doc(html_root_url = "https://docs.rs/r2d2_redis/0.14.0")]
3#![warn(missing_docs)]
4
5pub extern crate r2d2;
6pub extern crate redis;
7
8use std::error;
9use std::error::Error as _StdError;
10use std::fmt;
11
12use redis::ConnectionLike;
13
14/// A unified enum of errors returned by redis::Client
15#[derive(Debug)]
16pub enum Error {
17    /// A redis::RedisError
18    Other(redis::RedisError),
19}
20
21impl fmt::Display for Error {
22    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
23        #[allow(deprecated)] // `cause` is replaced by `Error:source` in 1.33
24        match self.cause() {
25            Some(cause) => write!(fmt, "{}: {}", self.description(), cause),
26            None => write!(fmt, "{}", self.description()),
27        }
28    }
29}
30
31impl error::Error for Error {
32    fn description(&self) -> &str {
33        match *self {
34            Error::Other(ref err) => err.description(),
35        }
36    }
37
38    fn cause(&self) -> Option<&dyn error::Error> {
39        match *self {
40            Error::Other(ref err) => {
41                #[allow(deprecated)] // `cause` is replaced by `Error:source` in 1.33
42                err.cause()
43            },
44        }
45    }
46}
47
48/// An `r2d2::ConnectionManager` for `redis::Client`s.
49///
50/// ## Example
51///
52
53/// ```
54/// extern crate r2d2_redis;
55///
56/// use std::ops::DerefMut;
57/// use std::thread;
58///
59/// use r2d2_redis::{r2d2, redis, RedisConnectionManager};
60///
61/// fn main() {
62///     let manager = RedisConnectionManager::new("redis://localhost").unwrap();
63///     let pool = r2d2::Pool::builder()
64///         .build(manager)
65///         .unwrap();
66///
67///     let mut handles = vec![];
68///
69///     for _i in 0..10i32 {
70///         let pool = pool.clone();
71///         handles.push(thread::spawn(move || {
72///             let mut conn = pool.get().unwrap();
73///             let reply = redis::cmd("PING").query::<String>(conn.deref_mut()).unwrap();
74///             // Alternatively, without deref():
75///             // let reply = redis::cmd("PING").query::<String>(&mut *conn).unwrap();
76///             assert_eq!("PONG", reply);
77///         }));
78///     }
79///
80///     for h in handles {
81///         h.join().unwrap();
82///     }
83/// }
84/// ```
85#[derive(Debug)]
86pub struct RedisConnectionManager {
87    connection_info: redis::ConnectionInfo,
88}
89
90impl RedisConnectionManager {
91    /// Creates a new `RedisConnectionManager`.
92    ///
93    /// See `redis::Client::open` for a description of the parameter
94    /// types.
95    pub fn new<T: redis::IntoConnectionInfo>(
96        params: T,
97    ) -> Result<RedisConnectionManager, redis::RedisError> {
98        Ok(RedisConnectionManager {
99            connection_info: params.into_connection_info()?,
100        })
101    }
102}
103
104impl r2d2::ManageConnection for RedisConnectionManager {
105    type Connection = redis::Connection;
106    type Error = Error;
107
108    fn connect(&self) -> Result<redis::Connection, Error> {
109        match redis::Client::open(self.connection_info.clone()) {
110            Ok(client) => client.get_connection().map_err(Error::Other),
111            Err(err) => Err(Error::Other(err)),
112        }
113    }
114
115    fn is_valid(&self, conn: &mut redis::Connection) -> Result<(), Error> {
116        redis::cmd("PING").query(conn).map_err(Error::Other)
117    }
118
119    fn has_broken(&self, conn: &mut redis::Connection) -> bool {
120        !conn.is_open()
121    }
122}