apomesh-state-store-redis
The Redis cache primitive for the production state-store stack. This
crate is deliberately not a StateStore implementation — the
substrate’s persistence boundary is the StateStore trait, which the
Postgres adapter’s
HybridStateStore implements while composing this cache inward.
HybridStateStore delegates snapshots and the memory tiers to Postgres
(durable) and routes hot working-memory reads plus an event-log replay
buffer through RedisCache (the hot path). Reach for this crate only
when composing or wiring that hybrid stack — never as a standalone store.
Position in the workspace
Section titled “Position in the workspace”- Layer: state stores — a typed cache primitive within the deployment-persistence layer, composed by an adapter rather than sitting behind a store port itself. See The event log for the event log and working-memory model it caches.
- Depends on:
apomesh-substrate — for the
TenantIdandSessionIdtypes the keys are built from. - Consumed by:
apomesh-state-store-postgres
(
HybridStateStorecomposes it inward) and apomesh-orchestrator-bin (connects the cache at boot and hands it to the hybrid store).
What it owns
Section titled “What it owns”RedisCache— the typed cache handle, wrapping aredis::aio::ConnectionManager(a single multiplexed connection with reconnect-on-drop, not a pool).Clone, andDebug-redacted so an auth-bearing connection string never surfaces in logs.- The key layout — tenant-prefixed working-memory keys
(
apomesh:tenant:{tenant}:agent:{agent}:working, a single serialisedAgentSnapshotblob) and per-session event-log streams (apomesh:session:{session}:events, Redis Stream entries). Every key is tenant-prefixed so aKEYS apomesh:tenant:X:*sweep maps to all of tenant X’s hot state. - TTL-bounded working memory —
working_memory_putsets an expiry (theHybridStateStoresupplies it from operator config) so a cache entry evicts rather than growing indefinitely; an explicitworking_memory_invalidatedrops an entry when the authoritative Postgres copy is overwritten. RedisCacheError— a two-variant error vocabulary (Connect,Io) theHybridStateStoreboundary maps intoStateStoreError; both variants mean “cache unavailable, fall back to Postgres.”
Public surface
Section titled “Public surface”Verified against lib.rs:
RedisCache::connect(url) -> Result<Self, RedisCacheError>— connect to a Redis URL (e.g.redis://localhost:6379); reconnects transparently on transient failure.RedisCache::from_connection(conn)— wrap an already-builtConnectionManager(used by container-backed tests).working_memory_get(tenant, agent_uuid) -> Result<Option<Vec<u8>>>—Ok(None)on a miss, so the caller falls back to Postgres and back-populates.working_memory_put(tenant, agent_uuid, bytes, ttl)— write-through with an expiry.working_memory_invalidate(tenant, agent_uuid) -> Result<u64>— drop a stale entry; returns the number of keys removed.event_log_buffer_append(session, envelope) -> Result<String>— append to a session’s hot event-log stream; returns the Redis-assigned entry id.ping() -> Result<()>— operator-driven liveness check.
use std::time::Duration;use apomesh_state_store_redis::RedisCache;
# async fn demo(tenant: &apomesh_substrate::agent::TenantId) -> anyhow::Result<()> {let cache = RedisCache::connect("redis://localhost:6379").await?;
// Write-through with a 24h TTL, then read the cached bytes back.cache .working_memory_put(tenant, "agent-uuid", b"snapshot-bytes".to_vec(), Duration::from_secs(86_400)) .await?;let cached: Option<Vec<u8>> = cache.working_memory_get(tenant, "agent-uuid").await?;assert!(cached.is_some());# Ok(())# }In a deployment you do not call RedisCache directly — the
HybridStateStore owns every call site. This example shows the primitive
in isolation.
Related
Section titled “Related”- Reference:
apomesh-state-store-postgres
— the adapter that composes this cache into
HybridStateStore. - Operate: Local stack — where the Redis service comes up alongside Postgres in the Compose stack.