Redis session cache
When session storage runs on Postgres, WednesdayAI can front it with a Redis hot cache (session.storage.cache: "redis"). The cache is a strictly-optional accelerator: every read path falls back to Postgres on any miss, timeout, or error, and writes always go through Postgres first. Implementation: src/config/sessions/ctx-redis-cache.ts (CtxRedisCache), wired in src/config/sessions/storage-config.ts.
This page is written for developers extending or debugging the storage layer. Operators configuring the cache can jump to For administrators.
Write-through pattern
After every conversation append commits to Postgres, the cache is updated in a write-through step (afterAppend):
- Cursor write —
SET ctx:<sessionId>:cursor <cursor JSON> EX <ttl>records the new storage cursor (seq, entry id,rawSha256). - Tail invalidation —
DEL ctx:<sessionId>:taildrops the cached transcript tail, so the next read repopulates it from Postgres.
backend, sessionId, seq, rawSha256). Any append changes the cursor, which invalidates derived payloads by comparison rather than by explicit purge.
What is cached
Payloads larger than 64 KiB serialized are never cached, and tail entries carrying
metadata.largePayloadRefs are skipped — oversized blobs stay Postgres-only so the cache stays fast.
Degradation semantics
The cache is designed to be silently disposable:- Operation timeout: 250 ms. Any Redis op slower than that is abandoned and the Postgres path serves the read.
- Connect timeout: 1 s; close timeout: 250 ms. A cache that cannot come up at gateway start is skipped (
redis ctx cache unavailable; continuing without cache). - Failures log at most once per 60 s (
Redis ctx cache operation failed; continuing from Postgres) instead of per operation. - Missing
redisUrllogsredis ctx cache requires session.storage.redisUrl; continuing without cacheand starts cacheless.
Configuration surface
Resolved byresolveSessionStorageConfig (src/config/sessions/storage-config.ts):
Internal knobs (not config-exposed, from
CtxRedisCacheOptions): operationTimeoutMs 250, maxPayloadBytes 64 KiB, failureLogIntervalMs 60 000.
For administrators
Enable the cache on an existing Postgres session storage:- The cache takes effect at gateway startup — restart after changing these keys (Linux:
systemctl --user restart openclaw-gateway; macOS:wednesdayai gateway restart --deep). cache: "redis"withoutbackend: "postgres"is ignored (SQLite and JSONL backends have no Redis cache path).- Redis going down or being flushed is safe: reads fall back to Postgres automatically and logged warnings are rate-limited to once a minute. Expect elevated Postgres load and slower tail reads during an outage — nothing else changes.
- The cache stores derived/correlated data only; Postgres remains the sole durable store. Do not point
ttlSecondsat retention expectations — TTL only bounds staleness of cached copies. redis(thenode-redisclient) is loaded lazily; only Postgres+cache installs need it available.
consumerClaims block.
Extending from a plugin
Plugins do not talk to this cache directly — they see it through storage reads (ConversationReadQuery on the context-engine hooks) which are already cache-accelerated. If your plugin adds its own projections, key them by session and validate against the storage cursor before reuse, mirroring CtxRedisCache.readProjection:
sessionId without the cursor — an append between your read and your reuse silently serves stale context.
Related
- Context engine — the read paths this cache accelerates
- Sessions — storage backends, maintenance, and privacy
- Plugin hooks reference —
storage.afterAppendand context hooks