fix: don't panic in redis library on creating connection pool (#494)

This commit is contained in:
Kartikeya Hegde
2023-02-03 12:43:42 +05:30
committed by GitHub
parent 0441d5cdde
commit aa58d3466b
5 changed files with 30 additions and 18 deletions

View File

@ -5,10 +5,13 @@ use crate::settings::Database;
pub type PgPool = bb8::Pool<async_bb8_diesel::ConnectionManager<PgConnection>>; pub type PgPool = bb8::Pool<async_bb8_diesel::ConnectionManager<PgConnection>>;
#[allow(clippy::expect_used)]
pub async fn redis_connection( pub async fn redis_connection(
conf: &crate::settings::Settings, conf: &crate::settings::Settings,
) -> redis_interface::RedisConnectionPool { ) -> redis_interface::RedisConnectionPool {
redis_interface::RedisConnectionPool::new(&conf.redis).await redis_interface::RedisConnectionPool::new(&conf.redis)
.await
.expect("Failed to create Redis connection Pool")
} }
#[allow(clippy::expect_used)] #[allow(clippy::expect_used)]

View File

@ -589,7 +589,9 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn test_consumer_group_create() { async fn test_consumer_group_create() {
let redis_conn = RedisConnectionPool::new(&RedisSettings::default()).await; let redis_conn = RedisConnectionPool::new(&RedisSettings::default())
.await
.unwrap();
let result1 = redis_conn let result1 = redis_conn
.consumer_group_create("TEST1", "GTEST", &RedisEntryId::AutoGeneratedID) .consumer_group_create("TEST1", "GTEST", &RedisEntryId::AutoGeneratedID)

View File

@ -52,4 +52,6 @@ pub enum RedisError {
NotFound, NotFound,
#[error("Invalid RedisEntryId provided")] #[error("Invalid RedisEntryId provided")]
InvalidRedisEntryId, InvalidRedisEntryId,
#[error("Failed to establish Redis connection")]
RedisConnectionError,
} }

View File

@ -21,6 +21,8 @@ pub mod commands;
pub mod errors; pub mod errors;
pub mod types; pub mod types;
use common_utils::errors::CustomResult;
use error_stack::{IntoReport, ResultExt};
use router_env::logger; use router_env::logger;
pub use self::{commands::*, types::*}; pub use self::{commands::*, types::*};
@ -28,17 +30,12 @@ pub use self::{commands::*, types::*};
pub struct RedisConnectionPool { pub struct RedisConnectionPool {
pub pool: fred::pool::RedisPool, pub pool: fred::pool::RedisPool,
config: RedisConfig, config: RedisConfig,
_join_handles: Vec<fred::types::ConnectHandle>, join_handles: Vec<fred::types::ConnectHandle>,
} }
impl RedisConnectionPool { impl RedisConnectionPool {
/// Create a new Redis connection /// Create a new Redis connection
/// pub async fn new(conf: &RedisSettings) -> CustomResult<Self, errors::RedisError> {
/// # Panics
///
/// Panics if a connection to Redis is not successful.
#[allow(clippy::expect_used)]
pub async fn new(conf: &RedisSettings) -> Self {
let redis_connection_url = match conf.cluster_enabled { let redis_connection_url = match conf.cluster_enabled {
// Fred relies on this format for specifying cluster where the host port is ignored & only query parameters are used for node addresses // Fred relies on this format for specifying cluster where the host port is ignored & only query parameters are used for node addresses
// redis-cluster://username:password@host:port?node=bar.com:30002&node=baz.com:30003 // redis-cluster://username:password@host:port?node=bar.com:30002&node=baz.com:30003
@ -58,7 +55,9 @@ impl RedisConnectionPool {
), ),
}; };
let mut config = fred::types::RedisConfig::from_url(&redis_connection_url) let mut config = fred::types::RedisConfig::from_url(&redis_connection_url)
.expect("Invalid Redis connection URL"); .into_report()
.change_context(errors::RedisError::RedisConnectionError)?;
if !conf.use_legacy_version { if !conf.use_legacy_version {
config.version = fred::types::RespVersion::RESP3; config.version = fred::types::RespVersion::RESP3;
} }
@ -68,24 +67,27 @@ impl RedisConnectionPool {
conf.reconnect_delay, conf.reconnect_delay,
); );
let pool = fred::pool::RedisPool::new(config, conf.pool_size) let pool = fred::pool::RedisPool::new(config, conf.pool_size)
.expect("Unable to construct Redis pool"); .into_report()
.change_context(errors::RedisError::RedisConnectionError)?;
let _join_handles = pool.connect(Some(policy)); let join_handles = pool.connect(Some(policy));
pool.wait_for_connect() pool.wait_for_connect()
.await .await
.expect("Error connecting to Redis"); .into_report()
.change_context(errors::RedisError::RedisConnectionError)?;
let config = RedisConfig::from(conf); let config = RedisConfig::from(conf);
Self { Ok(Self {
pool, pool,
config, config,
_join_handles, join_handles,
} })
} }
pub async fn close_connections(&mut self) { pub async fn close_connections(&mut self) {
self.pool.quit_pool().await; self.pool.quit_pool().await;
for handle in self._join_handles.drain(..) { for handle in self.join_handles.drain(..) {
match handle.await { match handle.await {
Ok(Ok(_)) => (), Ok(Ok(_)) => (),
Ok(Err(error)) => logger::error!(%error), Ok(Err(error)) => logger::error!(%error),

View File

@ -26,10 +26,13 @@ impl CustomizeConnection<PgPooledConn, ConnectionError> for TestTransaction {
} }
} }
#[allow(clippy::expect_used)]
pub async fn redis_connection( pub async fn redis_connection(
conf: &crate::configs::settings::Settings, conf: &crate::configs::settings::Settings,
) -> redis_interface::RedisConnectionPool { ) -> redis_interface::RedisConnectionPool {
redis_interface::RedisConnectionPool::new(&conf.redis).await redis_interface::RedisConnectionPool::new(&conf.redis)
.await
.expect("Failed to create Redis Connection Pool")
} }
#[allow(clippy::expect_used)] #[allow(clippy::expect_used)]