use thiserror::Error;
use crate::cache_redis::RedisClusterRedirect;
pub type RedisCacheResult<T> = Result<T, RedisCacheError>;
#[derive(Debug, Error)]
pub enum RedisCacheError {
#[error("invalid redis url `{url}`")]
InvalidUrl {
url: String,
},
#[error("invalid redis cache config: {0}")]
InvalidConfig(String),
#[error("redis connection error: {0}")]
Connection(String),
#[error("redis command timed out: {0}")]
Timeout(String),
#[error("redis cluster redirect: {0:?}")]
ClusterRedirect(RedisClusterRedirect),
#[error(
"too many redis cluster redirects after {attempts} attempts for key fingerprint {key_fingerprint}"
)]
TooManyClusterRedirects {
attempts: u32,
key_fingerprint: String,
},
#[error("redis delete retry queue is full")]
RetryQueueFull,
#[error("redis circuit breaker rejected command: {0}")]
BreakerOpen(String),
#[error("redis cache serialization error: {0}")]
Serde(#[from] serde_json::Error),
#[error("redis backend error: {0}")]
Backend(String),
}
impl RedisCacheError {
pub fn too_many_cluster_redirects(attempts: u32, key: &str) -> Self {
Self::TooManyClusterRedirects {
attempts,
key_fingerprint: sanitized_key_fingerprint(key),
}
}
}
fn sanitized_key_fingerprint(key: &str) -> String {
let mut hash = 14_695_981_039_346_656_037u64;
for byte in key.as_bytes() {
hash ^= u64::from(*byte);
hash = hash.wrapping_mul(1_099_511_628_211);
}
format!("fnv64:{hash:016x}")
}