Caching¶
Cache strategy for dichit-backend. Caching lives behind the CacheService/cache contracts in src/application/interfaces/cache with a Redis implementation in src/infrastructure/cache/redis.
What to cache¶
| Data | Cache | TTL | Notes |
|---|---|---|---|
| Reference data (locations, IFSC, FAQs) | Redis | long (hours/days) | rarely changes |
| Public config / versions | Redis | medium | gate app-update policy |
| Expensive aggregations (dashboards) | Redis | short (seconds-minutes) | invalidate on write |
| WebSocket snapshots | Redis | session-bound | replay after reconnect |
| Auth / rate-limit state | Redis | session-bound | per-request |
Do not cache mutable per-user state (balances, bid state) unless the invalidation path is explicit — consistency beats a cache hit here.
Key design¶
- Namespaced keys:
dichit:<domain>:<id>:<variant>. - Always set a TTL — no unbounded keys.
- Include the cache version in the key when the shape changes (
…:v2:…) to avoid stale parsing.
Flow¶
flowchart LR
UC["Use case"] --> C{"CacheService"}
C -->|"hit"| H["return cached DTO"]
C -->|"miss"| DB["DB / provider"]
DB --> SET["cache.set(key, value, ttl)"]
SET --> OUT["return fresh value"] Invalidation¶
- Write-through: update/delete paths invalidate the affected keys inside the same unit of work where feasible.
- TTL as safety net: never rely on invalidation alone.
- Versioned keys for breaking shape changes.
- Cache-bust on deploy of a new cacheable shape: bump the key version.
Failure behaviour¶
- Cache misses should fall through to the source of truth, not error.
- If Redis is down, reads must degrade gracefully (no request failure caused by cache), per redis-down.md.
Best practices¶
- Measure hit-rate and per-key size; prune unused namespaces.
- Keep serialized payloads small (use the DTO shape, not raw rows).
- Never cache secrets, OTPs, or PII beyond what the contract requires.