use std::time::Duration;
use crate::error::CacheError;
use crate::key::KeyRef;
use crate::tier::TierId;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BackendKind {
InMemory,
InMemoryFallback,
Moka,
Redis,
Sled,
RocksDb,
Postgres,
Neo4j,
Helix,
Oxigraph,
Origin,
Test,
Unavailable,
}
impl BackendKind {
#[must_use]
pub fn is_native(&self) -> bool {
!matches!(
self,
Self::InMemoryFallback | Self::Unavailable | Self::Test
)
}
#[must_use]
pub fn is_persistent(&self) -> bool {
matches!(self, Self::Sled | Self::RocksDb | Self::Postgres)
}
#[must_use]
pub fn is_shared(&self) -> bool {
matches!(
self,
Self::Redis | Self::Postgres | Self::Neo4j | Self::Helix | Self::Origin
)
}
}
impl std::fmt::Display for BackendKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
Self::InMemory => "in-memory",
Self::InMemoryFallback => "in-memory-fallback",
Self::Moka => "moka",
Self::Redis => "redis",
Self::Sled => "sled",
Self::RocksDb => "rocksdb",
Self::Postgres => "postgres",
Self::Neo4j => "neo4j",
Self::Helix => "helix",
Self::Oxigraph => "oxigraph",
Self::Origin => "origin",
Self::Test => "test",
Self::Unavailable => "unavailable",
};
f.write_str(s)
}
}
#[async_trait::async_trait]
pub trait CacheTier<V>: Send + Sync {
fn name(&self) -> String;
fn backend(&self) -> BackendKind;
async fn get(&self, key: &KeyRef<'_>) -> Result<Option<V>, CacheError>;
async fn set(
&self,
key: &KeyRef<'_>,
value: V,
ttl: Option<Duration>,
) -> Result<(), CacheError>;
async fn remove(&self, key: &KeyRef<'_>) -> Result<(), CacheError>;
async fn contains(&self, key: &KeyRef<'_>) -> Result<bool, CacheError>;
fn health(&self) -> TierHealth;
fn tier_id(&self) -> TierId;
}
#[derive(Debug, Clone)]
pub struct TierHealth {
pub consecutive_failures: u64,
pub last_failure_timestamp: Option<std::time::SystemTime>,
pub health_score: f64,
pub availability: f64,
}
impl Default for TierHealth {
fn default() -> Self {
TierHealth {
consecutive_failures: 0,
last_failure_timestamp: None,
health_score: 1.0,
availability: 1.0,
}
}
}
impl TierHealth {
pub fn healthy(&self) -> bool {
self.consecutive_failures == 0
}
pub fn is_circuit_open(&self) -> bool {
self.consecutive_failures >= 5
}
}