feat: use postcard for redis serde (#6956)

* redo error handling in xredis

* give proper types to metadata fields

* add round-trip tests

* inline loader enum metadata fields

* postcard roundtrips

* prepare

* bump redis key version

* serde-binhum

* clippy

* fix

* fix frontend checking existence of component fields rather than non-null-ness

* prepare
This commit is contained in:
aecsocket
2026-08-05 10:36:05 +00:00
committed by GitHub
parent cc53d9a6f8
commit 5148e8ec35
70 changed files with 1713 additions and 646 deletions
+34 -24
View File
@@ -1,14 +1,14 @@
use std::time::Duration;
use eyre::{Result, WrapErr, bail};
use prometheus::Registry;
use super::RedisPool;
use super::config::{RedisConfig, RedisTopology};
use super::connection::RedisBackendBuildError;
use super::metrics::{
LogicalPoolStatus, LogicalPoolStatusProvider,
register_blocking_pool_metrics,
};
use super::{Error, RedisPool};
const POOL_RETAIN_INTERVAL: Duration = Duration::from_secs(30);
const MAX_IDLE_CONNECTION_AGE: Duration = Duration::from_secs(5 * 60);
@@ -27,9 +27,7 @@ enum RedisBlockingPoolInner {
}
impl RedisBlockingPool {
pub(super) async fn new(
config: &RedisConfig,
) -> Result<Self, RedisBackendBuildError> {
pub(super) async fn new(config: &RedisConfig) -> Result<Self> {
let pool_size = config.blocking_pool_size();
let inner = match config.topology() {
RedisTopology::Standalone => {
@@ -39,14 +37,16 @@ impl RedisBlockingPool {
let manager = deadpool_redis::Manager::new_with_config(
config.seed_urls()[0].clone(),
connection_config,
)?;
)
.wrap_err("configuring standalone blocking Redis client")?;
let pool = deadpool_redis::Pool::builder(manager)
.max_size(pool_size.max())
.wait_timeout(Some(Duration::from_millis(
config.wait_timeout_ms(),
)))
.runtime(deadpool_redis::Runtime::Tokio1)
.build()?;
.build()
.wrap_err("building standalone blocking Redis pool")?;
retain_standalone_pool(pool.clone());
RedisBlockingPoolInner::Standalone(pool)
}
@@ -54,14 +54,16 @@ impl RedisBlockingPool {
let manager = deadpool_redis::cluster::Manager::new(
config.seed_urls().to_vec(),
false,
)?;
)
.wrap_err("configuring clustered blocking Redis client")?;
let pool = deadpool_redis::cluster::Pool::builder(manager)
.max_size(pool_size.max())
.wait_timeout(Some(Duration::from_millis(
config.wait_timeout_ms(),
)))
.runtime(deadpool_redis::Runtime::Tokio1)
.build()?;
.build()
.wrap_err("building clustered blocking Redis pool")?;
retain_cluster_pool(pool.clone());
RedisBlockingPoolInner::Cluster(pool)
}
@@ -70,10 +72,7 @@ impl RedisBlockingPool {
Ok(Self { inner })
}
pub(super) fn register_metrics(
&self,
registry: &Registry,
) -> Result<(), prometheus::Error> {
pub(super) fn register_metrics(&self, registry: &Registry) -> Result<()> {
register_blocking_pool_metrics(registry, self.clone())
}
@@ -81,22 +80,33 @@ impl RedisBlockingPool {
&self,
key: &str,
timeout: Duration,
) -> Result<Option<[Vec<u8>; 2]>, Error> {
) -> Result<Option<[Vec<u8>; 2]>> {
if timeout.is_zero() {
return Err(Error::InvalidBlockingTimeout);
bail!("redis blocking timeout must be greater than zero");
}
let mut command = redis::cmd("BRPOP");
command.arg(key).arg(timeout.as_secs_f64());
let response: Option<(Vec<u8>, Vec<u8>)> = match &self.inner {
RedisBlockingPoolInner::Standalone(pool) => {
command.query_async(&mut pool.get().await?).await?
}
RedisBlockingPoolInner::Cluster(pool) => {
command.query_async(&mut pool.get().await?).await?
}
};
let response: Option<(Vec<u8>, Vec<u8>)> =
match &self.inner {
RedisBlockingPoolInner::Standalone(pool) => {
let mut connection = pool.get().await.wrap_err(
"fetching standalone blocking Redis connection",
)?;
command.query_async(&mut connection).await.wrap_err(
"reading from standalone Redis blocking queue",
)?
}
RedisBlockingPoolInner::Cluster(pool) => {
let mut connection = pool.get().await.wrap_err(
"fetching clustered blocking Redis connection",
)?;
command.query_async(&mut connection).await.wrap_err(
"reading from clustered Redis blocking queue",
)?
}
};
Ok(response.map(|(key, value)| [key, value]))
}
@@ -120,7 +130,7 @@ impl RedisPool {
&self,
key: &str,
timeout: Duration,
) -> Result<Option<[Vec<u8>; 2]>, Error> {
) -> Result<Option<[Vec<u8>; 2]>> {
self.blocking.brpop(key, timeout).await
}
}