Skip to content

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

  1. Write-through: update/delete paths invalidate the affected keys inside the same unit of work where feasible.
  2. TTL as safety net: never rely on invalidation alone.
  3. Versioned keys for breaking shape changes.
  4. 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.