From 24902a9ff4b174698dca0bbf1e00719b5bd726a0 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Mon, 3 Nov 2025 14:52:01 +0100 Subject: [PATCH 01/11] feat(redis): Add connection and response timeouts This adds connection and respnose timeout config options for both Single and Cluster Redis clients. Unfortunately, since `redis` and `deadpool-redis` don't provide enough knobs to tweak the default clients, the easiest way to accomplish this is by more or less reinventing `deadpool_redis::Manager` and `deadpool_redis::Cluster::Manager`, but with timeouts applied. Consequently the `deadpool_redis` dependency becomes unused. TBD: default values and docstrings for the new timeouts. --- Cargo.lock | 11 ----- Cargo.toml | 1 - relay-config/src/redis.rs | 6 +++ relay-redis/Cargo.toml | 5 +- relay-redis/src/config.rs | 4 ++ relay-redis/src/pool.rs | 94 ++++++++++++++++++++++++++++++-------- relay-redis/src/real.rs | 12 ++--- relay-redis/src/scripts.rs | 2 +- 8 files changed, 93 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ced5a3c301..5bd5be602d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -998,16 +998,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "deadpool-redis" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c136f185b3ca9d1f4e4e19c11570e1002f4bfdd592d589053e225716d613851f" -dependencies = [ - "deadpool", - "redis", -] - [[package]] name = "deadpool-runtime" version = "0.1.4" @@ -4272,7 +4262,6 @@ name = "relay-redis" version = "25.10.0" dependencies = [ "deadpool", - "deadpool-redis", "futures", "redis", "relay-statsd", diff --git a/Cargo.toml b/Cargo.toml index 8425e54be09..fbed8362fbb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -106,7 +106,6 @@ criterion = "0.5.1" crossbeam-channel = "0.5.15" data-encoding = "2.9.0" deadpool = "0.12.3" -deadpool-redis = "0.20.0" debugid = "0.8.0" dialoguer = "0.11.0" dynfmt = "0.1.5" diff --git a/relay-config/src/redis.rs b/relay-config/src/redis.rs index 6063c613137..9154aa0172a 100644 --- a/relay-config/src/redis.rs +++ b/relay-config/src/redis.rs @@ -39,6 +39,8 @@ pub struct PartialRedisConfigOptions { /// blocking when the pool is exhausted. #[serde(skip_serializing_if = "Option::is_none")] pub wait_timeout: Option, + pub connection_timeout: Option, + pub response_timeout: Option, /// Sets the number of times after which the connection will check whether it is active when /// being recycled. /// @@ -55,6 +57,8 @@ impl Default for PartialRedisConfigOptions { create_timeout: Some(3), recycle_timeout: Some(2), wait_timeout: None, + connection_timeout: todo!(), + response_timeout: todo!(), recycle_check_frequency: 100, } } @@ -224,6 +228,8 @@ fn build_redis_config_options( create_timeout: options.create_timeout, recycle_timeout: options.recycle_timeout, wait_timeout: options.wait_timeout, + connection_timeout: options.connection_timeout, + response_timeout: options.response_timeout, recycle_check_frequency: options.recycle_check_frequency, } } diff --git a/relay-redis/Cargo.toml b/relay-redis/Cargo.toml index e3ace18b19b..52b2832910a 100644 --- a/relay-redis/Cargo.toml +++ b/relay-redis/Cargo.toml @@ -13,8 +13,7 @@ publish = false workspace = true [dependencies] -deadpool = { workspace = true, optional = true } -deadpool-redis = { workspace = true, optional = true, features = ["rt_tokio_1", "cluster", "script"] } +deadpool = { workspace = true, optional = true, features = ["rt_tokio_1"] } futures = { workspace = true } redis = { workspace = true, optional = true, features = [ "cluster", @@ -35,4 +34,4 @@ relay-system = { workspace = true } [features] default = [] -impl = ["dep:deadpool", "dep:deadpool-redis", "dep:relay-statsd", "dep:redis"] +impl = ["dep:deadpool", "dep:relay-statsd", "dep:redis"] diff --git a/relay-redis/src/config.rs b/relay-redis/src/config.rs index 776d209bdf6..41362b69bec 100644 --- a/relay-redis/src/config.rs +++ b/relay-redis/src/config.rs @@ -27,6 +27,8 @@ pub struct RedisConfigOptions { /// will fail with a timeout error. This setting helps prevent indefinite /// blocking when the pool is exhausted. pub wait_timeout: Option, + pub connection_timeout: Option, + pub response_timeout: Option, /// Sets the number of times after which the connection will check whether it is active when /// being recycled. /// @@ -43,6 +45,8 @@ impl Default for RedisConfigOptions { create_timeout: Some(3), recycle_timeout: Some(2), wait_timeout: None, + connection_timeout: todo!(), + response_timeout: todo!(), recycle_check_frequency: 100, } } diff --git a/relay-redis/src/pool.rs b/relay-redis/src/pool.rs index 07272d32afa..49d30d5c7cf 100644 --- a/relay-redis/src/pool.rs +++ b/relay-redis/src/pool.rs @@ -1,9 +1,12 @@ use deadpool::managed::{Manager, Metrics, Object, Pool, RecycleError, RecycleResult}; -use deadpool_redis::Manager as SingleManager; -use deadpool_redis::cluster::Manager as ClusterManager; use futures::FutureExt; +use redis::AsyncConnectionConfig; +use redis::cluster::ClusterClientBuilder; use std::ops::{Deref, DerefMut}; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::time::Duration; +use crate::RedisConfigOptions; use crate::redis; use crate::redis::aio::MultiplexedConnection; use crate::redis::cluster_async::ClusterConnection; @@ -135,9 +138,9 @@ impl redis::aio::ConnectionLike for CustomClusterConnection { /// This manager handles the creation and recycling of Redis cluster connections, /// ensuring proper connection health through periodic PING checks. It supports both /// primary and replica nodes, with optional read-from-replicas functionality. -#[derive(Debug)] pub struct CustomClusterManager { - manager: ClusterManager, + client: redis::cluster::ClusterClient, + ping_number: AtomicUsize, recycle_check_frequency: usize, } @@ -149,11 +152,24 @@ impl CustomClusterManager { pub fn new( params: Vec, read_from_replicas: bool, - recycle_check_frequency: usize, + options: RedisConfigOptions, ) -> RedisResult { + let mut client = ClusterClientBuilder::new(params); + + if read_from_replicas { + client = client.read_from_replicas(); + } + if let Some(connection_timeout) = options.connection_timeout { + client = client.connection_timeout(Duration::from_secs(connection_timeout)); + } + if let Some(response_timeout) = options.response_timeout { + client = client.response_timeout(Duration::from_secs(response_timeout)); + } + Ok(Self { - manager: ClusterManager::new(params, read_from_replicas)?, - recycle_check_frequency, + client: client.build()?, + ping_number: AtomicUsize::new(0), + recycle_check_frequency: options.recycle_check_frequency, }) } } @@ -163,7 +179,8 @@ impl Manager for CustomClusterManager { type Error = RedisError; async fn create(&self) -> Result, RedisError> { - self.manager.create().await.map(TrackedConnection::from) + let conn = self.client.get_async_connection().await?; + Ok(TrackedConnection::new(conn)) } async fn recycle( @@ -188,7 +205,19 @@ impl Manager for CustomClusterManager { return Ok(()); } - self.manager.recycle(conn, metrics).await + // Copied from deadpool_redis::cluster::Manager + let ping_number = self.ping_number.fetch_add(1, Ordering::Relaxed).to_string(); + let n = redis::cmd("PING") + .arg(&ping_number) + .query_async::(conn) + .await?; + if n == ping_number { + Ok(()) + } else { + Err(deadpool::managed::RecycleError::message( + "Invalid PING response", + )) + } } } @@ -229,7 +258,9 @@ impl redis::aio::ConnectionLike for CustomSingleConnection { /// ensuring proper connection health through periodic PING checks. It supports /// multiplexed connections for efficient handling of multiple operations. pub struct CustomSingleManager { - manager: SingleManager, + client: redis::Client, + ping_number: AtomicUsize, + connection_config: AsyncConnectionConfig, recycle_check_frequency: usize, } @@ -238,13 +269,21 @@ impl CustomSingleManager { /// /// The manager will establish and maintain connections to the specified Redis /// instance, handling connection lifecycle and health checks. - pub fn new( - params: T, - recycle_check_frequency: usize, - ) -> RedisResult { + pub fn new(params: T, options: RedisConfigOptions) -> RedisResult { + let mut connection_config = AsyncConnectionConfig::new(); + if let Some(connection_timeout) = options.connection_timeout { + connection_config = + connection_config.set_connection_timeout(Duration::from_secs(connection_timeout)); + } + if let Some(response_timeout) = options.response_timeout { + connection_config = + connection_config.set_response_timeout(Duration::from_secs(response_timeout)); + } Ok(Self { - manager: SingleManager::new(params)?, - recycle_check_frequency, + client: redis::Client::open(params)?, + ping_number: AtomicUsize::new(0), + connection_config, + recycle_check_frequency: options.recycle_check_frequency, }) } } @@ -254,7 +293,10 @@ impl Manager for CustomSingleManager { type Error = RedisError; async fn create(&self) -> Result, RedisError> { - self.manager.create().await.map(TrackedConnection::from) + self.client + .get_multiplexed_async_connection_with_config(&self.connection_config) + .await + .map(TrackedConnection::from) } async fn recycle( @@ -279,7 +321,23 @@ impl Manager for CustomSingleManager { return Ok(()); } - self.manager.recycle(conn, metrics).await + // Copied from deadpool_redis::Manager::recycle + let ping_number = self.ping_number.fetch_add(1, Ordering::Relaxed).to_string(); + // Using pipeline to avoid roundtrip for UNWATCH + let (n,) = redis::Pipeline::with_capacity(2) + .cmd("UNWATCH") + .ignore() + .cmd("PING") + .arg(&ping_number) + .query_async::<(String,)>(conn) + .await?; + if n == ping_number { + Ok(()) + } else { + Err(deadpool::managed::RecycleError::message( + "Invalid PING response", + )) + } } } diff --git a/relay-redis/src/real.rs b/relay-redis/src/real.rs index ceea40c7b8b..b3653c5f96b 100644 --- a/relay-redis/src/real.rs +++ b/relay-redis/src/real.rs @@ -1,5 +1,5 @@ +use deadpool::Runtime; use deadpool::managed::{BuildError, Manager, Metrics, Object, Pool, PoolError}; -use deadpool_redis::{ConfigError, Runtime}; use redis::{Cmd, Pipeline, RedisFuture, Value}; use std::time::Duration; use thiserror::Error; @@ -34,10 +34,6 @@ pub enum RedisError { /// An error that occurs when creating a Redis connection pool. #[error("failed to create redis pool: {0}")] CreatePool(#[from] BuildError), - - /// An error that occurs when configuring Redis. - #[error("failed to configure redis: {0}")] - ConfigError(#[from] ConfigError), } /// A collection of Redis clients used by Relay for different purposes. @@ -104,7 +100,7 @@ impl AsyncRedisClient { // We use our custom cluster manager which performs recycling in a different way from the // default manager. - let manager = pool::CustomClusterManager::new(servers, false, opts.recycle_check_frequency) + let manager = pool::CustomClusterManager::new(servers, false, opts.clone()) .map_err(RedisError::Redis)?; let pool = Self::build_pool(manager, opts)?; @@ -122,8 +118,8 @@ impl AsyncRedisClient { pub fn single(server: &str, opts: &RedisConfigOptions) -> Result { // We use our custom single manager which performs recycling in a different way from the // default manager. - let manager = pool::CustomSingleManager::new(server, opts.recycle_check_frequency) - .map_err(RedisError::Redis)?; + let manager = + pool::CustomSingleManager::new(server, opts.clone()).map_err(RedisError::Redis)?; let pool = Self::build_pool(manager, opts)?; diff --git a/relay-redis/src/scripts.rs b/relay-redis/src/scripts.rs index 6dfaa188b52..a49c8f1e845 100644 --- a/relay-redis/src/scripts.rs +++ b/relay-redis/src/scripts.rs @@ -1,4 +1,4 @@ -use deadpool_redis::redis::Script; +use redis::Script; use std::sync::OnceLock; /// A collection of static methods to load predefined Redis scripts. From 733c28769ce3351cbd7fe66cc52b17564c603c62 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Tue, 4 Nov 2025 14:54:19 +0100 Subject: [PATCH 02/11] Set default timeout values --- relay-config/src/redis.rs | 4 ++-- relay-redis/src/config.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/relay-config/src/redis.rs b/relay-config/src/redis.rs index 9154aa0172a..b48f497d699 100644 --- a/relay-config/src/redis.rs +++ b/relay-config/src/redis.rs @@ -57,8 +57,8 @@ impl Default for PartialRedisConfigOptions { create_timeout: Some(3), recycle_timeout: Some(2), wait_timeout: None, - connection_timeout: todo!(), - response_timeout: todo!(), + connection_timeout: Some(3), + response_timeout: Some(5), recycle_check_frequency: 100, } } diff --git a/relay-redis/src/config.rs b/relay-redis/src/config.rs index 41362b69bec..7f402af2455 100644 --- a/relay-redis/src/config.rs +++ b/relay-redis/src/config.rs @@ -45,8 +45,8 @@ impl Default for RedisConfigOptions { create_timeout: Some(3), recycle_timeout: Some(2), wait_timeout: None, - connection_timeout: todo!(), - response_timeout: todo!(), + connection_timeout: Some(3), + response_timeout: Some(5), recycle_check_frequency: 100, } } From 89723af2db64a21c8d507572cd05bea9b2da9523 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Tue, 4 Nov 2025 14:59:58 +0100 Subject: [PATCH 03/11] Make timeouts detach the connection --- relay-redis/src/pool.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/relay-redis/src/pool.rs b/relay-redis/src/pool.rs index 49d30d5c7cf..613507a41f8 100644 --- a/relay-redis/src/pool.rs +++ b/relay-redis/src/pool.rs @@ -44,9 +44,9 @@ impl TrackedConnection { /// from the pool. /// /// An `Ok` result never leads to the connection being detached. - /// A [`RedisError`] leads to the connection being detached if it is unrecoverable. + /// A [`RedisError`] leads to the connection being detached if it is either unrecoverable or a timeout. fn should_be_detached(result: Result) -> bool { - result.is_err_and(|error| error.is_unrecoverable_error()) + result.is_err_and(|error| error.is_unrecoverable_error() || error.is_timeout()) } } From e01b4aaa2b5d9efa8ff9f93d82cbbe79ab1361fb Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Tue, 4 Nov 2025 15:06:40 +0100 Subject: [PATCH 04/11] Increase response_timeout to 6s --- relay-config/src/redis.rs | 2 +- relay-redis/src/config.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/relay-config/src/redis.rs b/relay-config/src/redis.rs index b48f497d699..dd6195449b1 100644 --- a/relay-config/src/redis.rs +++ b/relay-config/src/redis.rs @@ -58,7 +58,7 @@ impl Default for PartialRedisConfigOptions { recycle_timeout: Some(2), wait_timeout: None, connection_timeout: Some(3), - response_timeout: Some(5), + response_timeout: Some(6), recycle_check_frequency: 100, } } diff --git a/relay-redis/src/config.rs b/relay-redis/src/config.rs index 7f402af2455..bb76c4f2409 100644 --- a/relay-redis/src/config.rs +++ b/relay-redis/src/config.rs @@ -46,7 +46,7 @@ impl Default for RedisConfigOptions { recycle_timeout: Some(2), wait_timeout: None, connection_timeout: Some(3), - response_timeout: Some(5), + response_timeout: Some(6), recycle_check_frequency: 100, } } From 52c1db703ad92baeab7c7e17f703998e599f3d92 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Tue, 4 Nov 2025 15:18:05 +0100 Subject: [PATCH 05/11] Remove connection_timeout --- relay-config/src/redis.rs | 3 --- relay-redis/src/config.rs | 2 -- relay-redis/src/pool.rs | 7 ------- 3 files changed, 12 deletions(-) diff --git a/relay-config/src/redis.rs b/relay-config/src/redis.rs index dd6195449b1..8c6a027e9f5 100644 --- a/relay-config/src/redis.rs +++ b/relay-config/src/redis.rs @@ -39,7 +39,6 @@ pub struct PartialRedisConfigOptions { /// blocking when the pool is exhausted. #[serde(skip_serializing_if = "Option::is_none")] pub wait_timeout: Option, - pub connection_timeout: Option, pub response_timeout: Option, /// Sets the number of times after which the connection will check whether it is active when /// being recycled. @@ -57,7 +56,6 @@ impl Default for PartialRedisConfigOptions { create_timeout: Some(3), recycle_timeout: Some(2), wait_timeout: None, - connection_timeout: Some(3), response_timeout: Some(6), recycle_check_frequency: 100, } @@ -228,7 +226,6 @@ fn build_redis_config_options( create_timeout: options.create_timeout, recycle_timeout: options.recycle_timeout, wait_timeout: options.wait_timeout, - connection_timeout: options.connection_timeout, response_timeout: options.response_timeout, recycle_check_frequency: options.recycle_check_frequency, } diff --git a/relay-redis/src/config.rs b/relay-redis/src/config.rs index bb76c4f2409..97cf095b73d 100644 --- a/relay-redis/src/config.rs +++ b/relay-redis/src/config.rs @@ -27,7 +27,6 @@ pub struct RedisConfigOptions { /// will fail with a timeout error. This setting helps prevent indefinite /// blocking when the pool is exhausted. pub wait_timeout: Option, - pub connection_timeout: Option, pub response_timeout: Option, /// Sets the number of times after which the connection will check whether it is active when /// being recycled. @@ -45,7 +44,6 @@ impl Default for RedisConfigOptions { create_timeout: Some(3), recycle_timeout: Some(2), wait_timeout: None, - connection_timeout: Some(3), response_timeout: Some(6), recycle_check_frequency: 100, } diff --git a/relay-redis/src/pool.rs b/relay-redis/src/pool.rs index 613507a41f8..b53c4a2b901 100644 --- a/relay-redis/src/pool.rs +++ b/relay-redis/src/pool.rs @@ -159,9 +159,6 @@ impl CustomClusterManager { if read_from_replicas { client = client.read_from_replicas(); } - if let Some(connection_timeout) = options.connection_timeout { - client = client.connection_timeout(Duration::from_secs(connection_timeout)); - } if let Some(response_timeout) = options.response_timeout { client = client.response_timeout(Duration::from_secs(response_timeout)); } @@ -271,10 +268,6 @@ impl CustomSingleManager { /// instance, handling connection lifecycle and health checks. pub fn new(params: T, options: RedisConfigOptions) -> RedisResult { let mut connection_config = AsyncConnectionConfig::new(); - if let Some(connection_timeout) = options.connection_timeout { - connection_config = - connection_config.set_connection_timeout(Duration::from_secs(connection_timeout)); - } if let Some(response_timeout) = options.response_timeout { connection_config = connection_config.set_response_timeout(Duration::from_secs(response_timeout)); From ea15bf738c6f3e7101b9221b950e580a50efea60 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Tue, 4 Nov 2025 15:19:46 +0100 Subject: [PATCH 06/11] Docs for `response_timeout` --- relay-config/src/redis.rs | 4 ++++ relay-redis/src/config.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/relay-config/src/redis.rs b/relay-config/src/redis.rs index 8c6a027e9f5..d0774d5b2ec 100644 --- a/relay-config/src/redis.rs +++ b/relay-config/src/redis.rs @@ -39,6 +39,10 @@ pub struct PartialRedisConfigOptions { /// blocking when the pool is exhausted. #[serde(skip_serializing_if = "Option::is_none")] pub wait_timeout: Option, + /// Sets the maximum time in seconds to wait for a result when sending a Redis command. + /// + /// If a command exceeds this timeout, the connection will be recycled. + #[serde(skip_serializing_if = "Option::is_none")] pub response_timeout: Option, /// Sets the number of times after which the connection will check whether it is active when /// being recycled. diff --git a/relay-redis/src/config.rs b/relay-redis/src/config.rs index 97cf095b73d..cb957e01228 100644 --- a/relay-redis/src/config.rs +++ b/relay-redis/src/config.rs @@ -27,6 +27,10 @@ pub struct RedisConfigOptions { /// will fail with a timeout error. This setting helps prevent indefinite /// blocking when the pool is exhausted. pub wait_timeout: Option, + /// Sets the maximum time in seconds to wait for a result when sending a Redis command. + /// + /// If a command exceeds this timeout, the connection will be recycled. + #[serde(skip_serializing_if = "Option::is_none")] pub response_timeout: Option, /// Sets the number of times after which the connection will check whether it is active when /// being recycled. From a5c18f4b376a6ed5f78c891bd4042844c64412fd Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Tue, 4 Nov 2025 15:21:50 +0100 Subject: [PATCH 07/11] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15dfc76af2d..62cae27b136 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Normalize deprecated attribute names according to `sentry-conventions` for logs and V2 spans. ([#5257](https://github.com/getsentry/relay/pull/5257)) - Allow sample rate per trace metric. ([#5317](https://github.com/getsentry/relay/pull/5317)) - Replace `is_remote` with `is_segment` on the Span V2 schema. ([#5306](https://github.com/getsentry/relay/pull/5306)) +- Add `response_timeout` config setting for Redis. ([#5329](https://github.com/getsentry/relay/pull/5329)) **Breaking Changes**: From 5cf11a2959d66fce24c21a4b7026377fdd169dc4 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Wed, 5 Nov 2025 15:18:46 +0100 Subject: [PATCH 08/11] Unnecessary qualified uses --- relay-redis/src/pool.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/relay-redis/src/pool.rs b/relay-redis/src/pool.rs index b53c4a2b901..d26a351b85e 100644 --- a/relay-redis/src/pool.rs +++ b/relay-redis/src/pool.rs @@ -211,9 +211,7 @@ impl Manager for CustomClusterManager { if n == ping_number { Ok(()) } else { - Err(deadpool::managed::RecycleError::message( - "Invalid PING response", - )) + Err(RecycleError::message("Invalid PING response")) } } } @@ -327,9 +325,7 @@ impl Manager for CustomSingleManager { if n == ping_number { Ok(()) } else { - Err(deadpool::managed::RecycleError::message( - "Invalid PING response", - )) + Err(RecycleError::message("Invalid PING response")) } } } From e599b029fe33873112b137f3c5cd0093721a7e46 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Wed, 5 Nov 2025 15:18:58 +0100 Subject: [PATCH 09/11] Add justification for detach on timeout --- relay-redis/src/pool.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/relay-redis/src/pool.rs b/relay-redis/src/pool.rs index d26a351b85e..ddf1698933d 100644 --- a/relay-redis/src/pool.rs +++ b/relay-redis/src/pool.rs @@ -45,6 +45,7 @@ impl TrackedConnection { /// /// An `Ok` result never leads to the connection being detached. /// A [`RedisError`] leads to the connection being detached if it is either unrecoverable or a timeout. + /// In case of timeout, we would rather close a potentially dead connection and establish a new one. fn should_be_detached(result: Result) -> bool { result.is_err_and(|error| error.is_unrecoverable_error() || error.is_timeout()) } From 81524d73cab86c5530cd4e49215e52a105b844c0 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Thu, 6 Nov 2025 10:15:54 +0100 Subject: [PATCH 10/11] Increase default response_timeout to 30s --- relay-config/src/redis.rs | 2 +- relay-redis/src/config.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/relay-config/src/redis.rs b/relay-config/src/redis.rs index d0774d5b2ec..eea872d7494 100644 --- a/relay-config/src/redis.rs +++ b/relay-config/src/redis.rs @@ -60,7 +60,7 @@ impl Default for PartialRedisConfigOptions { create_timeout: Some(3), recycle_timeout: Some(2), wait_timeout: None, - response_timeout: Some(6), + response_timeout: Some(30), recycle_check_frequency: 100, } } diff --git a/relay-redis/src/config.rs b/relay-redis/src/config.rs index cb957e01228..0faebd7aaca 100644 --- a/relay-redis/src/config.rs +++ b/relay-redis/src/config.rs @@ -48,7 +48,7 @@ impl Default for RedisConfigOptions { create_timeout: Some(3), recycle_timeout: Some(2), wait_timeout: None, - response_timeout: Some(6), + response_timeout: Some(30), recycle_check_frequency: 100, } } From 1b6b8ca24c3efc5d26c6f14f801102cdf19877e6 Mon Sep 17 00:00:00 2001 From: Sebastian Zivota Date: Thu, 6 Nov 2025 10:54:52 +0100 Subject: [PATCH 11/11] Fix snapshots --- relay-config/src/redis.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/relay-config/src/redis.rs b/relay-config/src/redis.rs index eea872d7494..5ec3ba205db 100644 --- a/relay-config/src/redis.rs +++ b/relay-config/src/redis.rs @@ -410,6 +410,7 @@ quotas: "idle_timeout": 60, "create_timeout": 3, "recycle_timeout": 2, + "response_timeout": 30, "recycle_check_frequency": 100 } "###); @@ -432,6 +433,7 @@ quotas: "idle_timeout": 60, "create_timeout": 3, "recycle_timeout": 2, + "response_timeout": 30, "recycle_check_frequency": 100 } "###); @@ -551,6 +553,7 @@ max_connections: 20 "idle_timeout": 60, "create_timeout": 3, "recycle_timeout": 2, + "response_timeout": 30, "recycle_check_frequency": 100 } "###); @@ -579,6 +582,7 @@ max_connections: 20 "idle_timeout": 60, "create_timeout": 3, "recycle_timeout": 2, + "response_timeout": 30, "recycle_check_frequency": 100 } "###); @@ -618,6 +622,7 @@ max_connections: 20 "idle_timeout": 60, "create_timeout": 3, "recycle_timeout": 2, + "response_timeout": 30, "recycle_check_frequency": 100 }, "cardinality": { @@ -625,6 +630,7 @@ max_connections: 20 "idle_timeout": 60, "create_timeout": 3, "recycle_timeout": 2, + "response_timeout": 30, "recycle_check_frequency": 100 }, "quotas": { @@ -636,6 +642,7 @@ max_connections: 20 "idle_timeout": 60, "create_timeout": 3, "recycle_timeout": 2, + "response_timeout": 30, "recycle_check_frequency": 100 } }