From 93b3b70616a3ac5d36877ad71367c111ad4aa127 Mon Sep 17 00:00:00 2001 From: Maurus Decimus <11444311+mdecimus@users.noreply.github.com> Date: Thu, 25 Jun 2026 10:26:23 +0200 Subject: [PATCH] Redis Sentinel support as an in-memory store and cluster coordinator backend (closes #2430) --- CHANGELOG.md | 1 + Cargo.lock | 51 ++-- crates/coordinator/Cargo.toml | 2 +- .../coordinator/src/backend/redis/pubsub.rs | 25 ++ crates/coordinator/src/bootstrap.rs | 6 + crates/directory/Cargo.toml | 5 +- crates/directory/src/backend/ldap/pool.rs | 5 +- crates/jmap/src/registry/set.rs | 4 +- crates/registry/src/schema/enums.rs | 4 + crates/registry/src/schema/enums_impl.rs | 20 +- crates/registry/src/schema/properties.rs | 3 + crates/registry/src/schema/properties_impl.rs | 11 +- crates/registry/src/schema/structs.rs | 33 +++ crates/registry/src/schema/structs_impl.rs | 239 ++++++++++++++++++ crates/services/src/task_manager/acme.rs | 2 +- crates/smtp/src/outbound/delivery.rs | 2 +- crates/smtp/src/scripts/exec.rs | 9 +- crates/store/Cargo.toml | 8 +- crates/store/src/backend/postgres/main.rs | 7 +- crates/store/src/backend/postgres/mod.rs | 2 +- crates/store/src/backend/redis/lookup.rs | 44 +++- crates/store/src/backend/redis/mod.rs | 64 ++++- crates/store/src/backend/redis/pool.rs | 30 ++- crates/store/src/build/memory.rs | 4 + resources/schema/schema.json.gz | Bin 145994 -> 146243 bytes resources/schema/schema.json.sha256 | 2 +- tests/Cargo.toml | 4 +- 27 files changed, 527 insertions(+), 60 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bf07a42..175f3478 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ If you are upgrading from v0.16.x, replace the binary (or run `docker pull`). If ## Added - Encryption-at-rest: Support for `AES-256-GCM` and `ChaCha20-Poly1305` for S/MIME (#161). - S3: Support for `allowInvalidCerts` option to allow connecting to S3 endpoints with invalid TLS certificates. +- Redis Sentinel support as an in-memory store and cluster coordinator backend (#2430). ## Changed diff --git a/Cargo.lock b/Cargo.lock index 8aec4406..436d6481 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1858,24 +1858,23 @@ dependencies = [ [[package]] name = "deadpool" -version = "0.10.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb84100978c1c7b37f09ed3ce3e5f843af02c2a2c431bae5b19230dad2c1b490" +checksum = "0be2b1d1d6ec8d846f05e137292d0b89133caf95ef33695424c09568bdd39b1b" dependencies = [ - "async-trait", - "deadpool-runtime", + "deadpool-runtime 0.1.4", + "lazy_static", "num_cpus", "tokio", ] [[package]] name = "deadpool" -version = "0.12.3" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0be2b1d1d6ec8d846f05e137292d0b89133caf95ef33695424c09568bdd39b1b" +checksum = "883466cb8db62725aee5f4a6011e8a5d42912b42632df32aad57fc91127c6e04" dependencies = [ - "deadpool-runtime", - "lazy_static", + "deadpool-runtime 0.3.1", "num_cpus", "tokio", ] @@ -1903,6 +1902,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "deadpool-runtime" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2657f61fb1dd8bf37a8d51093cc7cee4e77125b22f7753f49b289f831bec2bae" +dependencies = [ + "tokio", +] + [[package]] name = "decancer" version = "3.3.3" @@ -2033,10 +2041,9 @@ version = "0.16.11" dependencies = [ "ahash", "argon2", - "async-trait", "base64 0.22.1", "compact_str", - "deadpool 0.10.0", + "deadpool 0.13.0", "futures", "jsonwebtoken", "ldap3", @@ -2598,9 +2605,9 @@ dependencies = [ [[package]] name = "foundationdb" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310c638e34e54f56daa986ed6c8dadecf4e4825245b73e577feb25c808222ae8" +checksum = "c9a0b9e89be4942ad3c6cf76789e7eaf9489fcca2b06b1449b2d9eb015424793" dependencies = [ "async-recursion", "async-trait", @@ -2609,7 +2616,7 @@ dependencies = [ "foundationdb-sys", "foundationdb-tuple", "futures", - "rand 0.9.4", + "rand 0.10.1", "serde", "serde_bytes", "serde_json", @@ -2619,18 +2626,18 @@ dependencies = [ [[package]] name = "foundationdb-gen" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b749fc82bb7576794d4679f166a5cfa0a856122e05635437f7231e5e679fa2f6" +checksum = "db58c729fca985f56d347e5f8df5c1d3135cc8211e5688eacf695e1365449594" dependencies = [ "xml-rs", ] [[package]] name = "foundationdb-macros" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4ca5370149145ec3741cd7e82832f17f893b9421ee4e484d9511c6702bd9911" +checksum = "0f51be872cad567c58cf475749b25b9bb96e9ab6063af8bbe4f965ecf40e13cb" dependencies = [ "proc-macro2", "quote", @@ -2640,9 +2647,9 @@ dependencies = [ [[package]] name = "foundationdb-sys" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0f3f231ff5b8465063b2bf8af3b975222b4fa3cc8c07b43d01fe8e0ae15c9dd" +checksum = "0bac3aa47fdd7af6ac1b2a8ee4684fe4ed3d6c663c7ff5888e1846a790e6601a" dependencies = [ "bindgen", "libc", @@ -2650,9 +2657,9 @@ dependencies = [ [[package]] name = "foundationdb-tuple" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8cd42c159de9b90a91efc0ce350e3142099571ef498e7fa1a1dcc1d1eeccd9d" +checksum = "3c5262f7a16bddd129d31d96d09de25dee2295ce7cccaa7ed6b212f391819c64" dependencies = [ "memchr", "uuid", @@ -7787,7 +7794,7 @@ dependencies = [ "blake3", "bytes", "compact_str", - "deadpool 0.12.3", + "deadpool 0.13.0", "deadpool-postgres", "farmhash", "flate2", diff --git a/crates/coordinator/Cargo.toml b/crates/coordinator/Cargo.toml index bd43fff3..e84503ae 100644 --- a/crates/coordinator/Cargo.toml +++ b/crates/coordinator/Cargo.toml @@ -13,7 +13,7 @@ tokio = { version = "1.47", features = ["sync", "fs", "io-util"] } async-nats = { version = "0.49", default-features = false, features = ["server_2_10", "server_2_11", "aws-lc-rs"], optional = true } zenoh = { version = "1.3.4", default-features = false, features = ["auth_pubkey", "transport_multilink", "transport_compression", "transport_quic", "transport_tcp", "transport_tls", "transport_udp"], optional = true } rdkafka = { version = "0.39", features = ["cmake-build"], optional = true } -redis = { version = "1.1", features = [ "tokio-comp", "tokio-rustls-comp", "tls-rustls-insecure", "tls-rustls", "cluster-async"], optional = true } +redis = { version = "1.1", features = [ "tokio-comp", "tokio-rustls-comp", "tls-rustls-insecure", "tls-rustls", "cluster-async", "sentinel"], optional = true } [features] nats = ["async-nats", "futures"] diff --git a/crates/coordinator/src/backend/redis/pubsub.rs b/crates/coordinator/src/backend/redis/pubsub.rs index ec5e9322..547f1ecd 100644 --- a/crates/coordinator/src/backend/redis/pubsub.rs +++ b/crates/coordinator/src/backend/redis/pubsub.rs @@ -42,6 +42,14 @@ pub(crate) async fn redis_publish( .publish(topic, message) .await .map_err(into_error), + RedisPool::Sentinel(pool) => pool + .get() + .await + .map_err(into_error)? + .as_mut() + .publish(topic, message) + .await + .map_err(into_error), } } @@ -80,6 +88,23 @@ pub(crate) async fn redis_subscribe( rx, })) } + RedisPool::Sentinel(pool) => { + let client = pool + .manager() + .client + .lock() + .await + .async_get_client() + .await + .map_err(into_error)?; + + let mut pubsub = client.get_async_pubsub().await.map_err(into_error)?; + pubsub.subscribe(topic).await.map_err(into_error)?; + + Ok(PubSubStream::Redis(RedisPubSubStream { + stream: pubsub.into_on_message(), + })) + } } } diff --git a/crates/coordinator/src/bootstrap.rs b/crates/coordinator/src/bootstrap.rs index 56247f95..8cd35d67 100644 --- a/crates/coordinator/src/bootstrap.rs +++ b/crates/coordinator/src/bootstrap.rs @@ -48,6 +48,12 @@ impl Coordinator { .await .map(unwrap_redis) } + #[cfg(feature = "redis")] + structs::Coordinator::RedisSentinel(redis_sentinel_store) => { + store::backend::redis::RedisStore::open_sentinel(redis_sentinel_store) + .await + .map(unwrap_redis) + } _ => Err("Binary was not compiled with the selected coordinator backend".to_string()), }; diff --git a/crates/directory/Cargo.toml b/crates/directory/Cargo.toml index 8dca8d7e..269a2893 100644 --- a/crates/directory/Cargo.toml +++ b/crates/directory/Cargo.toml @@ -18,12 +18,11 @@ tokio-rustls = { version = "0.26", default-features = false, features = ["aws_lc rustls = { version = "0.23.5", default-features = false, features = ["std", "aws_lc_rs", "tls12"] } rustls-pki-types = { version = "1" } ldap3 = { version = "0.12", default-features = false, features = ["tls-rustls-aws-lc-rs"] } -deadpool = { version = "0.10", features = ["managed", "rt_tokio_1"] } -async-trait = "0.1.68" +deadpool = { version = "0.13", features = ["managed", "rt_tokio_1"] } ahash = { version = "0.8" } pwhash = "1" argon2 = "0.5.0" -pbkdf2 = {version = "0.12.1", features = ["simple"] } +pbkdf2 = { version = "0.12.1", features = ["simple"] } scrypt = "0.11.0" sha1 = "0.11" sha2 = "0.11" diff --git a/crates/directory/src/backend/ldap/pool.rs b/crates/directory/src/backend/ldap/pool.rs index d9df8259..a8913b79 100644 --- a/crates/directory/src/backend/ldap/pool.rs +++ b/crates/directory/src/backend/ldap/pool.rs @@ -4,13 +4,10 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ -use async_trait::async_trait; +use super::LdapConnectionManager; use deadpool::managed; use ldap3::{Ldap, LdapConnAsync, LdapError, exop::WhoAmI}; -use super::LdapConnectionManager; - -#[async_trait] impl managed::Manager for LdapConnectionManager { type Type = Ldap; type Error = LdapError; diff --git a/crates/jmap/src/registry/set.rs b/crates/jmap/src/registry/set.rs index 7ef6ca9c..cd938206 100644 --- a/crates/jmap/src/registry/set.rs +++ b/crates/jmap/src/registry/set.rs @@ -722,7 +722,9 @@ impl RegistrySet for Server { ObjectType::AccountSettings | ObjectType::ApiKey | ObjectType::AccountPassword - | ObjectType::AppPassword => account_set(set).await.map(|set| set.into_response()), + | ObjectType::AppPassword => Box::pin(account_set(set)) + .await + .map(|set| set.into_response()), ObjectType::QueuedMessage => { queued_message_set(set).await.map(|set| set.into_response()) diff --git a/crates/registry/src/schema/enums.rs b/crates/registry/src/schema/enums.rs index 68822b80..b749e8aa 100644 --- a/crates/registry/src/schema/enums.rs +++ b/crates/registry/src/schema/enums.rs @@ -270,6 +270,7 @@ pub enum CoordinatorType { Zenoh = 4, Redis = 5, RedisCluster = 6, + RedisSentinel = 7, } #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)] @@ -848,6 +849,7 @@ pub enum InMemoryStoreBaseType { #[default] Redis = 0, RedisCluster = 1, + RedisSentinel = 2, } #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)] @@ -858,6 +860,7 @@ pub enum InMemoryStoreType { Sharded = 1, Redis = 2, RedisCluster = 3, + RedisSentinel = 4, } #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)] @@ -1265,6 +1268,7 @@ pub enum LookupStoreType { Sharded = 3, Redis = 4, RedisCluster = 5, + RedisSentinel = 6, } #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)] diff --git a/crates/registry/src/schema/enums_impl.rs b/crates/registry/src/schema/enums_impl.rs index b33bb5a0..93d045ac 100644 --- a/crates/registry/src/schema/enums_impl.rs +++ b/crates/registry/src/schema/enums_impl.rs @@ -1402,6 +1402,7 @@ impl EnumImpl for CoordinatorType { b"Zenoh" => CoordinatorType::Zenoh, b"Redis" => CoordinatorType::Redis, b"RedisCluster" => CoordinatorType::RedisCluster, + b"RedisSentinel" => CoordinatorType::RedisSentinel, } } @@ -1414,6 +1415,7 @@ impl EnumImpl for CoordinatorType { CoordinatorType::Zenoh => "Zenoh", CoordinatorType::Redis => "Redis", CoordinatorType::RedisCluster => "RedisCluster", + CoordinatorType::RedisSentinel => "RedisSentinel", } } @@ -1430,11 +1432,12 @@ impl EnumImpl for CoordinatorType { 4 => Some(CoordinatorType::Zenoh), 5 => Some(CoordinatorType::Redis), 6 => Some(CoordinatorType::RedisCluster), + 7 => Some(CoordinatorType::RedisSentinel), _ => None, } } - const COUNT: usize = 7; + const COUNT: usize = 8; } impl serde::Serialize for CoordinatorType { @@ -4036,6 +4039,7 @@ impl EnumImpl for InMemoryStoreBaseType { value.as_bytes(), b"Redis" => InMemoryStoreBaseType::Redis, b"RedisCluster" => InMemoryStoreBaseType::RedisCluster, + b"RedisSentinel" => InMemoryStoreBaseType::RedisSentinel, } } @@ -4043,6 +4047,7 @@ impl EnumImpl for InMemoryStoreBaseType { match self { InMemoryStoreBaseType::Redis => "Redis", InMemoryStoreBaseType::RedisCluster => "RedisCluster", + InMemoryStoreBaseType::RedisSentinel => "RedisSentinel", } } @@ -4054,11 +4059,12 @@ impl EnumImpl for InMemoryStoreBaseType { match id { 0 => Some(InMemoryStoreBaseType::Redis), 1 => Some(InMemoryStoreBaseType::RedisCluster), + 2 => Some(InMemoryStoreBaseType::RedisSentinel), _ => None, } } - const COUNT: usize = 2; + const COUNT: usize = 3; } impl serde::Serialize for InMemoryStoreBaseType { @@ -4088,6 +4094,7 @@ impl EnumImpl for InMemoryStoreType { b"Sharded" => InMemoryStoreType::Sharded, b"Redis" => InMemoryStoreType::Redis, b"RedisCluster" => InMemoryStoreType::RedisCluster, + b"RedisSentinel" => InMemoryStoreType::RedisSentinel, } } @@ -4097,6 +4104,7 @@ impl EnumImpl for InMemoryStoreType { InMemoryStoreType::Sharded => "Sharded", InMemoryStoreType::Redis => "Redis", InMemoryStoreType::RedisCluster => "RedisCluster", + InMemoryStoreType::RedisSentinel => "RedisSentinel", } } @@ -4110,11 +4118,12 @@ impl EnumImpl for InMemoryStoreType { 1 => Some(InMemoryStoreType::Sharded), 2 => Some(InMemoryStoreType::Redis), 3 => Some(InMemoryStoreType::RedisCluster), + 4 => Some(InMemoryStoreType::RedisSentinel), _ => None, } } - const COUNT: usize = 4; + const COUNT: usize = 5; } impl serde::Serialize for InMemoryStoreType { @@ -5489,6 +5498,7 @@ impl EnumImpl for LookupStoreType { b"Sharded" => LookupStoreType::Sharded, b"Redis" => LookupStoreType::Redis, b"RedisCluster" => LookupStoreType::RedisCluster, + b"RedisSentinel" => LookupStoreType::RedisSentinel, } } @@ -5500,6 +5510,7 @@ impl EnumImpl for LookupStoreType { LookupStoreType::Sharded => "Sharded", LookupStoreType::Redis => "Redis", LookupStoreType::RedisCluster => "RedisCluster", + LookupStoreType::RedisSentinel => "RedisSentinel", } } @@ -5515,11 +5526,12 @@ impl EnumImpl for LookupStoreType { 3 => Some(LookupStoreType::Sharded), 4 => Some(LookupStoreType::Redis), 5 => Some(LookupStoreType::RedisCluster), + 6 => Some(LookupStoreType::RedisSentinel), _ => None, } } - const COUNT: usize = 6; + const COUNT: usize = 7; } impl serde::Serialize for LookupStoreType { diff --git a/crates/registry/src/schema/properties.rs b/crates/registry/src/schema/properties.rs index b7254e72..5fc70e72 100644 --- a/crates/registry/src/schema/properties.rs +++ b/crates/registry/src/schema/properties.rs @@ -1023,10 +1023,13 @@ pub enum Property { SelectorTemplate = 226, SendFrequency = 230, SendingMtaIp = 833, + SentinelSecret = 915, + SentinelUsername = 914, Separator = 97, ServerHostname = 121, Servers = 308, ServiceAccountJson = 316, + ServiceName = 913, Services = 794, SessionToken = 329, SetMaxObjects = 440, diff --git a/crates/registry/src/schema/properties_impl.rs b/crates/registry/src/schema/properties_impl.rs index a6f27ba6..8ffc914a 100644 --- a/crates/registry/src/schema/properties_impl.rs +++ b/crates/registry/src/schema/properties_impl.rs @@ -1176,10 +1176,13 @@ impl EnumImpl for Property { b"selectorTemplate" => Property::SelectorTemplate, b"sendFrequency" => Property::SendFrequency, b"sendingMtaIp" => Property::SendingMtaIp, + b"sentinelSecret" => Property::SentinelSecret, + b"sentinelUsername" => Property::SentinelUsername, b"separator" => Property::Separator, b"serverHostname" => Property::ServerHostname, b"servers" => Property::Servers, b"serviceAccountJson" => Property::ServiceAccountJson, + b"serviceName" => Property::ServiceName, b"services" => Property::Services, b"sessionToken" => Property::SessionToken, b"setMaxObjects" => Property::SetMaxObjects, @@ -2094,10 +2097,13 @@ impl EnumImpl for Property { Property::SelectorTemplate => "selectorTemplate", Property::SendFrequency => "sendFrequency", Property::SendingMtaIp => "sendingMtaIp", + Property::SentinelSecret => "sentinelSecret", + Property::SentinelUsername => "sentinelUsername", Property::Separator => "separator", Property::ServerHostname => "serverHostname", Property::Servers => "servers", Property::ServiceAccountJson => "serviceAccountJson", + Property::ServiceName => "serviceName", Property::Services => "services", Property::SessionToken => "sessionToken", Property::SetMaxObjects => "setMaxObjects", @@ -3016,10 +3022,13 @@ impl EnumImpl for Property { 226 => Some(Property::SelectorTemplate), 230 => Some(Property::SendFrequency), 833 => Some(Property::SendingMtaIp), + 915 => Some(Property::SentinelSecret), + 914 => Some(Property::SentinelUsername), 97 => Some(Property::Separator), 121 => Some(Property::ServerHostname), 308 => Some(Property::Servers), 316 => Some(Property::ServiceAccountJson), + 913 => Some(Property::ServiceName), 794 => Some(Property::Services), 329 => Some(Property::SessionToken), 440 => Some(Property::SetMaxObjects), @@ -3164,7 +3173,7 @@ impl EnumImpl for Property { } } - const COUNT: usize = 913; + const COUNT: usize = 916; } impl serde::Serialize for Property { diff --git a/crates/registry/src/schema/structs.rs b/crates/registry/src/schema/structs.rs index b0ef5be9..7060358e 100644 --- a/crates/registry/src/schema/structs.rs +++ b/crates/registry/src/schema/structs.rs @@ -788,6 +788,7 @@ pub enum Coordinator { Zenoh(ZenohCoordinator), Redis(RedisStore), RedisCluster(RedisClusterStore), + RedisSentinel(RedisSentinelStore), } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -3075,6 +3076,7 @@ pub enum InMemoryStore { Sharded(ShardedInMemoryStore), Redis(RedisStore), RedisCluster(RedisClusterStore), + RedisSentinel(RedisSentinelStore), } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -3082,6 +3084,7 @@ pub enum InMemoryStore { pub enum InMemoryStoreBase { Redis(RedisStore), RedisCluster(RedisClusterStore), + RedisSentinel(RedisSentinelStore), } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -3258,6 +3261,7 @@ pub enum LookupStore { Sharded(ShardedInMemoryStore), Redis(RedisStore), RedisCluster(RedisClusterStore), + RedisSentinel(RedisSentinelStore), } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -4326,6 +4330,35 @@ pub struct RedisClusterStore { pub pool_timeout_recycle: Option, } +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(default)] +pub struct RedisSentinelStore { + #[serde(rename = "urls")] + pub urls: Map, + #[serde(rename = "serviceName")] + pub service_name: String, + #[serde(rename = "timeout")] + pub timeout: Duration, + #[serde(rename = "authUsername")] + pub auth_username: Option, + #[serde(rename = "authSecret")] + pub auth_secret: SecretKeyOptional, + #[serde(rename = "sentinelUsername")] + pub sentinel_username: Option, + #[serde(rename = "sentinelSecret")] + pub sentinel_secret: SecretKeyOptional, + #[serde(rename = "protocolVersion")] + pub protocol_version: RedisProtocol, + #[serde(rename = "poolMaxConnections")] + pub pool_max_connections: u64, + #[serde(rename = "poolTimeoutCreate")] + pub pool_timeout_create: Option, + #[serde(rename = "poolTimeoutWait")] + pub pool_timeout_wait: Option, + #[serde(rename = "poolTimeoutRecycle")] + pub pool_timeout_recycle: Option, +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(default)] pub struct RedisStore { diff --git a/crates/registry/src/schema/structs_impl.rs b/crates/registry/src/schema/structs_impl.rs index e0c718d0..cc947584 100644 --- a/crates/registry/src/schema/structs_impl.rs +++ b/crates/registry/src/schema/structs_impl.rs @@ -5723,6 +5723,7 @@ impl ObjectImpl for Coordinator { Coordinator::Zenoh(inner) => inner.validate(errors), Coordinator::Redis(inner) => inner.validate(errors), Coordinator::RedisCluster(inner) => inner.validate(errors), + Coordinator::RedisSentinel(inner) => inner.validate(errors), } } @@ -5764,6 +5765,10 @@ impl Pickle for Coordinator { 6u16.pickle(out); inner.pickle(out); } + Coordinator::RedisSentinel(inner) => { + 7u16.pickle(out); + inner.pickle(out); + } } } @@ -5776,6 +5781,7 @@ impl Pickle for Coordinator { 4 => Pickle::unpickle(stream).map(Coordinator::Zenoh), 5 => Pickle::unpickle(stream).map(Coordinator::Redis), 6 => Pickle::unpickle(stream).map(Coordinator::RedisCluster), + 7 => Pickle::unpickle(stream).map(Coordinator::RedisSentinel), _ => None, } } @@ -5829,6 +5835,13 @@ impl IntoValue for Coordinator { .insert_unchecked(Property::Type, JmapValue::Str("RedisCluster".into())); obj } + Coordinator::RedisSentinel(obj) => { + let mut obj = obj.into_value(); + obj.as_object_mut() + .unwrap() + .insert_unchecked(Property::Type, JmapValue::Str("RedisSentinel".into())); + obj + } } } } @@ -5850,6 +5863,9 @@ impl RegistryJsonPatch for Coordinator { CoordinatorType::RedisCluster => { *self = Coordinator::RedisCluster(Default::default()) } + CoordinatorType::RedisSentinel => { + *self = Coordinator::RedisSentinel(Default::default()) + } } } match self { @@ -5860,6 +5876,7 @@ impl RegistryJsonPatch for Coordinator { Coordinator::Zenoh(inner) => inner.patch(pointer, value), Coordinator::Redis(inner) => inner.patch(pointer, value), Coordinator::RedisCluster(inner) => inner.patch(pointer, value), + Coordinator::RedisSentinel(inner) => inner.patch(pointer, value), } } } @@ -5874,6 +5891,7 @@ impl Coordinator { Coordinator::Zenoh(_) => CoordinatorType::Zenoh, Coordinator::Redis(_) => CoordinatorType::Redis, Coordinator::RedisCluster(_) => CoordinatorType::RedisCluster, + Coordinator::RedisSentinel(_) => CoordinatorType::RedisSentinel, } } } @@ -22312,6 +22330,7 @@ impl ObjectImpl for InMemoryStore { InMemoryStore::Sharded(inner) => inner.validate(errors), InMemoryStore::Redis(inner) => inner.validate(errors), InMemoryStore::RedisCluster(inner) => inner.validate(errors), + InMemoryStore::RedisSentinel(inner) => inner.validate(errors), } } @@ -22342,6 +22361,10 @@ impl Pickle for InMemoryStore { 3u16.pickle(out); inner.pickle(out); } + InMemoryStore::RedisSentinel(inner) => { + 4u16.pickle(out); + inner.pickle(out); + } } } @@ -22351,6 +22374,7 @@ impl Pickle for InMemoryStore { 1 => Pickle::unpickle(stream).map(InMemoryStore::Sharded), 2 => Pickle::unpickle(stream).map(InMemoryStore::Redis), 3 => Pickle::unpickle(stream).map(InMemoryStore::RedisCluster), + 4 => Pickle::unpickle(stream).map(InMemoryStore::RedisSentinel), _ => None, } } @@ -22385,6 +22409,13 @@ impl IntoValue for InMemoryStore { .insert_unchecked(Property::Type, JmapValue::Str("RedisCluster".into())); obj } + InMemoryStore::RedisSentinel(obj) => { + let mut obj = obj.into_value(); + obj.as_object_mut() + .unwrap() + .insert_unchecked(Property::Type, JmapValue::Str("RedisSentinel".into())); + obj + } } } } @@ -22403,6 +22434,9 @@ impl RegistryJsonPatch for InMemoryStore { InMemoryStoreType::RedisCluster => { *self = InMemoryStore::RedisCluster(Default::default()) } + InMemoryStoreType::RedisSentinel => { + *self = InMemoryStore::RedisSentinel(Default::default()) + } } } match self { @@ -22410,6 +22444,7 @@ impl RegistryJsonPatch for InMemoryStore { InMemoryStore::Sharded(inner) => inner.patch(pointer, value), InMemoryStore::Redis(inner) => inner.patch(pointer, value), InMemoryStore::RedisCluster(inner) => inner.patch(pointer, value), + InMemoryStore::RedisSentinel(inner) => inner.patch(pointer, value), } } } @@ -22421,6 +22456,7 @@ impl InMemoryStore { InMemoryStore::Sharded(_) => InMemoryStoreType::Sharded, InMemoryStore::Redis(_) => InMemoryStoreType::Redis, InMemoryStore::RedisCluster(_) => InMemoryStoreType::RedisCluster, + InMemoryStore::RedisSentinel(_) => InMemoryStoreType::RedisSentinel, } } } @@ -22430,6 +22466,7 @@ impl InMemoryStoreBase { match self { InMemoryStoreBase::Redis(inner) => inner.validate(errors), InMemoryStoreBase::RedisCluster(inner) => inner.validate(errors), + InMemoryStoreBase::RedisSentinel(inner) => inner.validate(errors), } } } @@ -22451,6 +22488,10 @@ impl Pickle for InMemoryStoreBase { 1u16.pickle(out); inner.pickle(out); } + InMemoryStoreBase::RedisSentinel(inner) => { + 2u16.pickle(out); + inner.pickle(out); + } } } @@ -22458,6 +22499,7 @@ impl Pickle for InMemoryStoreBase { match u16::unpickle(stream)? { 0 => Pickle::unpickle(stream).map(InMemoryStoreBase::Redis), 1 => Pickle::unpickle(stream).map(InMemoryStoreBase::RedisCluster), + 2 => Pickle::unpickle(stream).map(InMemoryStoreBase::RedisSentinel), _ => None, } } @@ -22480,6 +22522,13 @@ impl IntoValue for InMemoryStoreBase { .insert_unchecked(Property::Type, JmapValue::Str("RedisCluster".into())); obj } + InMemoryStoreBase::RedisSentinel(obj) => { + let mut obj = obj.into_value(); + obj.as_object_mut() + .unwrap() + .insert_unchecked(Property::Type, JmapValue::Str("RedisSentinel".into())); + obj + } } } } @@ -22498,11 +22547,15 @@ impl RegistryJsonPatch for InMemoryStoreBase { InMemoryStoreBaseType::RedisCluster => { *self = InMemoryStoreBase::RedisCluster(Default::default()) } + InMemoryStoreBaseType::RedisSentinel => { + *self = InMemoryStoreBase::RedisSentinel(Default::default()) + } } } match self { InMemoryStoreBase::Redis(inner) => inner.patch(pointer, value), InMemoryStoreBase::RedisCluster(inner) => inner.patch(pointer, value), + InMemoryStoreBase::RedisSentinel(inner) => inner.patch(pointer, value), } } } @@ -22512,6 +22565,7 @@ impl InMemoryStoreBase { match self { InMemoryStoreBase::Redis(_) => InMemoryStoreBaseType::Redis, InMemoryStoreBase::RedisCluster(_) => InMemoryStoreBaseType::RedisCluster, + InMemoryStoreBase::RedisSentinel(_) => InMemoryStoreBaseType::RedisSentinel, } } } @@ -23553,6 +23607,7 @@ impl LookupStore { LookupStore::Sharded(inner) => inner.validate(errors), LookupStore::Redis(inner) => inner.validate(errors), LookupStore::RedisCluster(inner) => inner.validate(errors), + LookupStore::RedisSentinel(inner) => inner.validate(errors), } } } @@ -23590,6 +23645,10 @@ impl Pickle for LookupStore { 5u16.pickle(out); inner.pickle(out); } + LookupStore::RedisSentinel(inner) => { + 6u16.pickle(out); + inner.pickle(out); + } } } @@ -23601,6 +23660,7 @@ impl Pickle for LookupStore { 3 => Pickle::unpickle(stream).map(LookupStore::Sharded), 4 => Pickle::unpickle(stream).map(LookupStore::Redis), 5 => Pickle::unpickle(stream).map(LookupStore::RedisCluster), + 6 => Pickle::unpickle(stream).map(LookupStore::RedisSentinel), _ => None, } } @@ -23651,6 +23711,13 @@ impl IntoValue for LookupStore { .insert_unchecked(Property::Type, JmapValue::Str("RedisCluster".into())); obj } + LookupStore::RedisSentinel(obj) => { + let mut obj = obj.into_value(); + obj.as_object_mut() + .unwrap() + .insert_unchecked(Property::Type, JmapValue::Str("RedisSentinel".into())); + obj + } } } } @@ -23671,6 +23738,9 @@ impl RegistryJsonPatch for LookupStore { LookupStoreType::RedisCluster => { *self = LookupStore::RedisCluster(Default::default()) } + LookupStoreType::RedisSentinel => { + *self = LookupStore::RedisSentinel(Default::default()) + } } } match self { @@ -23680,6 +23750,7 @@ impl RegistryJsonPatch for LookupStore { LookupStore::Sharded(inner) => inner.patch(pointer, value), LookupStore::Redis(inner) => inner.patch(pointer, value), LookupStore::RedisCluster(inner) => inner.patch(pointer, value), + LookupStore::RedisSentinel(inner) => inner.patch(pointer, value), } } } @@ -23693,6 +23764,7 @@ impl LookupStore { LookupStore::Sharded(_) => LookupStoreType::Sharded, LookupStore::Redis(_) => LookupStoreType::Redis, LookupStore::RedisCluster(_) => LookupStoreType::RedisCluster, + LookupStore::RedisSentinel(_) => LookupStoreType::RedisSentinel, } } } @@ -32024,6 +32096,173 @@ impl RegistryJsonPropertyPatch for RedisClusterStore { } } +impl RedisSentinelStore { + fn validate(&self, errors: &mut Vec) -> bool { + let neb = errors.len(); + let value = &self.urls; + for value in value.iter() { + if value.is_empty() { + errors.push(ValidationError::required(Property::Urls)); + } + } + let value = &self.service_name; + if value.is_empty() { + errors.push(ValidationError::required(Property::ServiceName)); + } + if let Some(value) = &self.auth_username { + if value.is_empty() { + errors.push(ValidationError::required(Property::AuthUsername)); + } + } + let value = &self.auth_secret; + value.validate(errors); + if let Some(value) = &self.sentinel_username { + if value.is_empty() { + errors.push(ValidationError::required(Property::SentinelUsername)); + } + } + let value = &self.sentinel_secret; + value.validate(errors); + let value = &self.pool_max_connections; + if *value > 8192 { + errors.push(ValidationError::max_value( + Property::PoolMaxConnections, + 8192, + )); + } + if *value < 1 { + errors.push(ValidationError::min_value(Property::PoolMaxConnections, 1)); + } + errors.len() == neb + } +} + +impl Pickle for RedisSentinelStore { + fn pickle(&self, out: &mut Vec) { + self.urls.pickle(out); + self.service_name.pickle(out); + self.timeout.pickle(out); + self.auth_username.pickle(out); + self.auth_secret.pickle(out); + self.sentinel_username.pickle(out); + self.sentinel_secret.pickle(out); + self.protocol_version.pickle(out); + self.pool_max_connections.pickle(out); + self.pool_timeout_create.pickle(out); + self.pool_timeout_wait.pickle(out); + self.pool_timeout_recycle.pickle(out); + } + + fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option { + let mut this = Self::default(); + this.urls = Pickle::unpickle(stream)?; + this.service_name = Pickle::unpickle(stream)?; + this.timeout = Pickle::unpickle(stream)?; + this.auth_username = Pickle::unpickle(stream)?; + this.auth_secret = Pickle::unpickle(stream)?; + this.sentinel_username = Pickle::unpickle(stream)?; + this.sentinel_secret = Pickle::unpickle(stream)?; + this.protocol_version = Pickle::unpickle(stream)?; + this.pool_max_connections = Pickle::unpickle(stream)?; + this.pool_timeout_create = Pickle::unpickle(stream)?; + this.pool_timeout_wait = Pickle::unpickle(stream)?; + this.pool_timeout_recycle = Pickle::unpickle(stream)?; + Some(this) + } +} + +impl Default for RedisSentinelStore { + fn default() -> Self { + Self { + urls: Map::new(vec!["redis://127.0.0.1:26379".to_string()]), + service_name: "mymaster".to_string(), + timeout: Duration::from_millis(10000), + auth_username: Some("stalwart".to_string()), + auth_secret: Default::default(), + sentinel_username: Default::default(), + sentinel_secret: Default::default(), + protocol_version: RedisProtocol::Resp2, + pool_max_connections: 10u64, + pool_timeout_create: Some(Duration::from_millis(30000)), + pool_timeout_wait: Some(Duration::from_millis(30000)), + pool_timeout_recycle: Some(Duration::from_millis(30000)), + } + } +} + +impl IntoValue for RedisSentinelStore { + fn into_value(self) -> JmapValue<'static> { + let mut map = jmap_tools::Map::with_capacity(14); + map.insert_unchecked(Property::Urls, self.urls.into_value()); + map.insert_unchecked(Property::ServiceName, self.service_name.into_value()); + map.insert_unchecked(Property::Timeout, self.timeout.into_value()); + map.insert_unchecked(Property::AuthUsername, self.auth_username.into_value()); + map.insert_unchecked(Property::AuthSecret, self.auth_secret.into_value()); + map.insert_unchecked( + Property::SentinelUsername, + self.sentinel_username.into_value(), + ); + map.insert_unchecked(Property::SentinelSecret, self.sentinel_secret.into_value()); + map.insert_unchecked( + Property::ProtocolVersion, + self.protocol_version.into_value(), + ); + map.insert_unchecked( + Property::PoolMaxConnections, + self.pool_max_connections.into_value(), + ); + map.insert_unchecked( + Property::PoolTimeoutCreate, + self.pool_timeout_create.into_value(), + ); + map.insert_unchecked( + Property::PoolTimeoutWait, + self.pool_timeout_wait.into_value(), + ); + map.insert_unchecked( + Property::PoolTimeoutRecycle, + self.pool_timeout_recycle.into_value(), + ); + JmapValue::Object(map) + } +} + +impl RegistryJsonPropertyPatch for RedisSentinelStore { + fn patch_property<'x>( + &mut self, + mut pointer: JsonPointerPatch<'_>, + value: JmapValue<'x>, + ) -> PatchResult<'x> { + match pointer.next_property() { + Some(Property::Urls) => self + .urls + .patch(pointer.with_validators(&[StringValidator::Trim]), value), + Some(Property::ServiceName) => self + .service_name + .patch(pointer.with_validators(&[StringValidator::Trim]), value), + Some(Property::Timeout) => self.timeout.patch(pointer, value), + Some(Property::AuthUsername) => self + .auth_username + .patch(pointer.with_validators(&[StringValidator::Trim]), value), + Some(Property::AuthSecret) => self.auth_secret.patch(pointer, value), + Some(Property::SentinelUsername) => self + .sentinel_username + .patch(pointer.with_validators(&[StringValidator::Trim]), value), + Some(Property::SentinelSecret) => self.sentinel_secret.patch(pointer, value), + Some(Property::ProtocolVersion) => self.protocol_version.patch(pointer, value), + Some(Property::PoolMaxConnections) => self.pool_max_connections.patch(pointer, value), + Some(Property::PoolTimeoutCreate) => self.pool_timeout_create.patch(pointer, value), + Some(Property::PoolTimeoutWait) => self.pool_timeout_wait.patch(pointer, value), + Some(Property::PoolTimeoutRecycle) => self.pool_timeout_recycle.patch(pointer, value), + Some(Property::Type) => Ok(MaybeUnpatched::Unpatched { + property: Property::Type, + value, + }), + _ => Err(PatchError::new(pointer, "Invalid property")), + } + } +} + impl RedisStore { fn validate(&self, errors: &mut Vec) -> bool { let neb = errors.len(); diff --git a/crates/services/src/task_manager/acme.rs b/crates/services/src/task_manager/acme.rs index 28ee0532..37a86171 100644 --- a/crates/services/src/task_manager/acme.rs +++ b/crates/services/src/task_manager/acme.rs @@ -43,7 +43,7 @@ const MAX_RETRIES: u32 = 5; async fn acme_management(server: &Server, task: &TaskDomainManagement) -> trc::Result { let mut last_temporary_error = Ok(TaskResult::temporary("")); for retry in 0..MAX_RETRIES { - last_temporary_error = match server.acme_renew(task.domain_id).await { + last_temporary_error = match Box::pin(server.acme_renew(task.domain_id)).await { Ok(tasks) => return Ok(TaskResult::Success(tasks)), Err(err) => match err { AcmeError::Crypto(_) diff --git a/crates/smtp/src/outbound/delivery.rs b/crates/smtp/src/outbound/delivery.rs index 42bbef42..ffbb4628 100644 --- a/crates/smtp/src/outbound/delivery.rs +++ b/crates/smtp/src/outbound/delivery.rs @@ -85,7 +85,7 @@ impl QueuedMessage { // Attempt delivery let start_time = Instant::now(); - let queue_event = self.deliver_task(server.clone(), message).await; + let queue_event = Box::pin(self.deliver_task(server.clone(), message)).await; trc::event!( Delivery(DeliveryEvent::AttemptEnd), diff --git a/crates/smtp/src/scripts/exec.rs b/crates/smtp/src/scripts/exec.rs index cc5ac3f9..f3fb9d24 100644 --- a/crates/smtp/src/scripts/exec.rs +++ b/crates/smtp/src/scripts/exec.rs @@ -146,15 +146,16 @@ impl Session { script: Arc, params: ScriptParameters<'_>, ) -> ScriptResult { - self.server - .run_script( + Box::pin( + self.server.run_script( script_id, script, params .with_session_id(self.data.session_id) .with_envelope(&self.server, self, self.data.session_id) .await, - ) - .await + ), + ) + .await } } diff --git a/crates/store/Cargo.toml b/crates/store/Cargo.toml index 5e2bbbd3..56ee9520 100644 --- a/crates/store/Cargo.toml +++ b/crates/store/Cargo.toml @@ -10,7 +10,7 @@ nlp = { path = "../nlp" } trc = { path = "../trc" } registry = { path = "../registry" } rocksdb = { version = "0.24", optional = true, features = ["multi-threaded-cf"] } -foundationdb = { version = "0.10", features = ["embedded-fdb-include", "fdb-7_4"], optional = true } +foundationdb = { version = "0.11", features = ["embedded-fdb-include", "fdb-7_4"], optional = true } rusqlite = { version = "0.40", features = ["bundled"], optional = true } rust-s3 = { version = "0.37", default-features = false, features = ["tokio-rustls-tls"], optional = true } reqwest_s3 = { package = "reqwest", version = "0.12", default-features = false, features = ["rustls-tls-native-roots"], optional = true } @@ -44,8 +44,8 @@ mysql_async = { version = "0.36", default-features = false, features = ["default serde_json = { version = "1.0.64" } regex = "1.12" flate2 = "1.1" -redis = { version = "1.1", features = [ "tokio-comp", "tokio-rustls-comp", "tls-rustls-insecure", "tls-rustls", "cluster-async"], optional = true } -deadpool = { version = "0.12", features = ["managed"], optional = true } +redis = { version = "1.1", features = [ "tokio-comp", "tokio-rustls-comp", "tls-rustls-insecure", "tls-rustls", "cluster-async", "sentinel"], optional = true } +deadpool = { version = "0.13", features = ["managed"], optional = true } arc-swap = "1.6.0" bitpacking = "0.9.2" memchr = { version = "2.7" } @@ -71,7 +71,7 @@ s3 = ["rust-s3", "dep:reqwest_s3"] azure = ["azure_core", "azure_storage", "azure_storage_blobs", "futures"] # In-memory stores -redis = ["dep:redis", "deadpool", "futures"] +redis = ["dep:redis", "deadpool", "deadpool/rt_tokio_1", "futures"] enterprise = [] test_mode = [] diff --git a/crates/store/src/backend/postgres/main.rs b/crates/store/src/backend/postgres/main.rs index e37eab92..722988a4 100644 --- a/crates/store/src/backend/postgres/main.rs +++ b/crates/store/src/backend/postgres/main.rs @@ -14,8 +14,9 @@ use crate::{ *, }; use ::registry::schema::{enums::PostgreSqlRecyclingMethod, structs}; -use deadpool::managed::Object; -use deadpool_postgres::{Config, Manager, ManagerConfig, PoolConfig, RecyclingMethod, Runtime}; +use deadpool_postgres::{ + Config, ManagerConfig, Object, PoolConfig, RecyclingMethod, Runtime, +}; use tokio_postgres::NoTls; use utils::tls::rustls_client_config; @@ -169,7 +170,7 @@ impl PostgresStore { } async fn create_search_tables( - conn: &Object, + conn: &Object, ) -> trc::Result<()> { let table_name = T::index().psql_table(); let mut query = format!("CREATE TABLE IF NOT EXISTS {} (", table_name); diff --git a/crates/store/src/backend/postgres/mod.rs b/crates/store/src/backend/postgres/mod.rs index 5152aeb0..10572032 100644 --- a/crates/store/src/backend/postgres/mod.rs +++ b/crates/store/src/backend/postgres/mod.rs @@ -42,7 +42,7 @@ fn into_error(err: tokio_postgres::error::Error) -> trc::Error { } #[inline(always)] -fn into_pool_error(err: deadpool::managed::PoolError) -> trc::Error { +fn into_pool_error(err: deadpool_postgres::PoolError) -> trc::Error { trc::StoreEvent::PostgresqlError.reason(err) } diff --git a/crates/store/src/backend/redis/lookup.rs b/crates/store/src/backend/redis/lookup.rs index 07817bb6..079c3b9e 100644 --- a/crates/store/src/backend/redis/lookup.rs +++ b/crates/store/src/backend/redis/lookup.rs @@ -4,11 +4,9 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ -use redis::AsyncCommands; - -use crate::Deserialize; - use super::{RedisPool, RedisStore, into_error}; +use crate::Deserialize; +use redis::AsyncCommands; impl RedisStore { pub async fn key_set(&self, key: &[u8], value: &[u8], expires: Option) -> trc::Result<()> { @@ -31,6 +29,15 @@ impl RedisStore { ) .await } + RedisPool::Sentinel(pool) => { + self.key_set_( + pool.get().await.map_err(into_error)?.as_mut(), + key, + value, + expires, + ) + .await + } } } @@ -54,6 +61,15 @@ impl RedisStore { ) .await } + RedisPool::Sentinel(pool) => { + self.key_incr_( + pool.get().await.map_err(into_error)?.as_mut(), + key, + value, + expires, + ) + .await + } } } @@ -67,6 +83,10 @@ impl RedisStore { self.key_delete_(pool.get().await.map_err(into_error)?.as_mut(), key) .await } + RedisPool::Sentinel(pool) => { + self.key_delete_(pool.get().await.map_err(into_error)?.as_mut(), key) + .await + } } } @@ -80,6 +100,10 @@ impl RedisStore { self.key_delete_prefix_(pool.get().await.map_err(into_error)?.as_mut(), prefix) .await } + RedisPool::Sentinel(pool) => { + self.key_delete_prefix_(pool.get().await.map_err(into_error)?.as_mut(), prefix) + .await + } } } @@ -96,6 +120,10 @@ impl RedisStore { self.key_get_(pool.get().await.map_err(into_error)?.as_mut(), key) .await } + RedisPool::Sentinel(pool) => { + self.key_get_(pool.get().await.map_err(into_error)?.as_mut(), key) + .await + } } } @@ -109,6 +137,10 @@ impl RedisStore { self.counter_get_(pool.get().await.map_err(into_error)?.as_mut(), key) .await } + RedisPool::Sentinel(pool) => { + self.counter_get_(pool.get().await.map_err(into_error)?.as_mut(), key) + .await + } } } @@ -122,6 +154,10 @@ impl RedisStore { self.key_exists_(pool.get().await.map_err(into_error)?.as_mut(), key) .await } + RedisPool::Sentinel(pool) => { + self.key_exists_(pool.get().await.map_err(into_error)?.as_mut(), key) + .await + } } } diff --git a/crates/store/src/backend/redis/mod.rs b/crates/store/src/backend/redis/mod.rs index 087b5025..be2f7414 100644 --- a/crates/store/src/backend/redis/mod.rs +++ b/crates/store/src/backend/redis/mod.rs @@ -10,9 +10,10 @@ use deadpool::{ managed::{Manager, Pool}, }; use redis::{ - Client, ProtocolVersion, + Client, IntoConnectionInfo, ProtocolVersion, cluster::{ClusterClient, ClusterClientBuilder}, cluster_read_routing::RandomReplicaStrategy, + sentinel::{SentinelClient, SentinelClientBuilder, SentinelServerType}, }; use registry::{ schema::{enums::RedisProtocol, structs}, @@ -38,9 +39,15 @@ pub struct RedisClusterConnectionManager { timeout: std::time::Duration, } +pub struct RedisSentinelConnectionManager { + pub client: tokio::sync::Mutex, + timeout: std::time::Duration, +} + pub enum RedisPool { Single(Pool), Cluster(Pool), + Sentinel(Pool), } impl RedisStore { @@ -101,6 +108,60 @@ impl RedisStore { )?), }))) } + + pub async fn open_sentinel( + config: structs::RedisSentinelStore, + ) -> Result { + let mut sentinels = Vec::with_capacity(config.urls.len()); + for url in config.urls { + let info = url + .into_connection_info() + .map_err(|err| format!("Invalid Redis Sentinel URL: {err}"))?; + sentinels.push(info.addr().clone()); + } + + let mut builder = + SentinelClientBuilder::new(sentinels, config.service_name, SentinelServerType::Master) + .map_err(|err| format!("Failed to create Redis Sentinel client: {err:?}"))?; + + if let Some(value) = config.auth_username { + builder = builder.set_client_to_redis_username(value); + } + if let Some(value) = config.auth_secret.secret().await?.map(|v| v.into_owned()) { + builder = builder.set_client_to_redis_password(value); + } + if let Some(value) = config.sentinel_username { + builder = builder.set_client_to_sentinel_username(value); + } + if let Some(value) = config + .sentinel_secret + .secret() + .await? + .map(|v| v.into_owned()) + { + builder = builder.set_client_to_sentinel_password(value); + } + if matches!(config.protocol_version, RedisProtocol::Resp3) { + builder = builder.set_client_to_redis_protocol(ProtocolVersion::RESP3); + } + + let client = builder + .build() + .map_err(|err| format!("Failed to open Redis Sentinel client: {err:?}"))?; + + Ok(InMemoryStore::Redis(Arc::new(RedisStore { + pool: RedisPool::Sentinel(build_pool( + RedisSentinelConnectionManager { + client: tokio::sync::Mutex::new(client), + timeout: config.timeout.into_inner(), + }, + config.pool_max_connections, + config.pool_timeout_create, + config.pool_timeout_wait, + config.pool_timeout_recycle, + )?), + }))) + } } fn build_pool( @@ -130,6 +191,7 @@ impl std::fmt::Debug for RedisPool { match self { Self::Single(_) => f.debug_tuple("Single").finish(), Self::Cluster(_) => f.debug_tuple("Cluster").finish(), + Self::Sentinel(_) => f.debug_tuple("Sentinel").finish(), } } } diff --git a/crates/store/src/backend/redis/pool.rs b/crates/store/src/backend/redis/pool.rs index bcbe07a0..341b630e 100644 --- a/crates/store/src/backend/redis/pool.rs +++ b/crates/store/src/backend/redis/pool.rs @@ -4,14 +4,16 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ +use super::{ + RedisClusterConnectionManager, RedisConnectionManager, RedisSentinelConnectionManager, + into_error, +}; use deadpool::managed; use redis::{ aio::{ConnectionLike, MultiplexedConnection}, cluster_async::ClusterConnection, }; -use super::{RedisClusterConnectionManager, RedisConnectionManager, into_error}; - impl managed::Manager for RedisConnectionManager { type Type = MultiplexedConnection; type Error = trc::Error; @@ -59,3 +61,27 @@ impl managed::Manager for RedisClusterConnectionManager { .map_err(|err| managed::RecycleError::Backend(into_error(err))) } } + +impl managed::Manager for RedisSentinelConnectionManager { + type Type = MultiplexedConnection; + type Error = trc::Error; + + async fn create(&self) -> Result { + let mut client = self.client.lock().await; + match tokio::time::timeout(self.timeout, client.get_async_connection()).await { + Ok(conn) => conn.map_err(into_error), + Err(_) => Err(trc::StoreEvent::RedisError.ctx(trc::Key::Details, "Connection Timeout")), + } + } + + async fn recycle( + &self, + conn: &mut MultiplexedConnection, + _: &managed::Metrics, + ) -> managed::RecycleResult { + conn.req_packed_command(&redis::cmd("PING")) + .await + .map(|_| ()) + .map_err(|err| managed::RecycleError::Backend(into_error(err))) + } +} diff --git a/crates/store/src/build/memory.rs b/crates/store/src/build/memory.rs index d3eb4552..59705b0b 100644 --- a/crates/store/src/build/memory.rs +++ b/crates/store/src/build/memory.rs @@ -22,6 +22,10 @@ impl InMemoryStore { structs::InMemoryStore::RedisCluster(redis_cluster_store) => { crate::backend::redis::RedisStore::open_cluster(redis_cluster_store).await } + #[cfg(feature = "redis")] + structs::InMemoryStore::RedisSentinel(redis_sentinel_store) => { + crate::backend::redis::RedisStore::open_sentinel(redis_sentinel_store).await + } // SPDX-SnippetBegin // SPDX-FileCopyrightText: 2020 Stalwart Labs LLC // SPDX-License-Identifier: LicenseRef-SEL diff --git a/resources/schema/schema.json.gz b/resources/schema/schema.json.gz index d2bcb825a2a80ea4ab327a802ac72406370e4cda..a8181418fc77d17eb816f402a8c6b3bc5f5fd299 100644 GIT binary patch delta 145887 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