Skip to main content

awa_ui/
cache.rs

1use std::collections::HashMap;
2use std::sync::Arc;
3use std::time::Duration;
4
5use awa_model::admin;
6use awa_model::job::JobState;
7use awa_model::AwaError;
8use moka::future::Cache;
9
10/// Typed, TTL-based caches for the dashboard's hot endpoints.
11///
12/// Each endpoint gets its own `moka::future::Cache` so values are
13/// fully typed. Moka handles expiry, eviction, and request coalescing
14/// (`try_get_with` ensures only one in-flight fetch per key while
15/// concurrent callers wait).
16///
17/// All caches use a single `()` key since each stores one aggregated
18/// response value.
19#[derive(Clone)]
20pub struct DashboardCache {
21    pub stats: Cache<(), HashMap<JobState, i64>>,
22    pub queues: Cache<(), Vec<admin::QueueStats>>,
23    pub runtime: Cache<(), admin::RuntimeOverview>,
24    pub queue_runtime: Cache<(), Vec<admin::QueueRuntimeSummary>>,
25}
26
27fn build_cache<V: Clone + Send + Sync + 'static>(ttl: Duration) -> Cache<(), V> {
28    Cache::builder().time_to_live(ttl).max_capacity(1).build()
29}
30
31impl DashboardCache {
32    pub fn new(ttl: Duration) -> Self {
33        Self {
34            stats: build_cache(ttl),
35            queues: build_cache(ttl),
36            runtime: build_cache(ttl),
37            queue_runtime: build_cache(ttl),
38        }
39    }
40}
41
42/// Shared error wrapper so moka's `try_get_with` can propagate errors.
43///
44/// `AwaError` is not `Clone`, but moka requires the error from
45/// `try_get_with` to be `Clone + Send + Sync`. We wrap it in an `Arc`.
46#[derive(Debug, Clone)]
47pub struct CacheError(pub Arc<AwaError>);
48
49impl From<AwaError> for CacheError {
50    fn from(err: AwaError) -> Self {
51        Self(Arc::new(err))
52    }
53}