Skip to content

Redis GET Response Cache

Related: Access caching strategy (Auth access only — separate from this document).

FINAL for product data backends (Promoters, MusicData, Finance, Artists, Venues, Admin BFF).

Auth session Redis and Checkout transactional Redis are out of scope here.


Standardize GET response caching in data-processing backends via one global middleware per service. Frontends do not use Redis.


┌──────────┐ ┌──────────┐ ┌─────────────────────┐ ┌─────────────┐
│ Browser │ ───► │ Frontend │ ───► │ DATA BACKEND │ ───► │ Redis │
└──────────┘ └──────────┘ │ │ │ fast copy │
│ Promoters │ └──────┬──────┘
│ MusicData │ │
│ Finance │ │ empty?
│ Artists │ ▼
│ Venues │ ┌─────────────┐
│ Admin (BFF) │ │ DB / API │
└─────────────────────┘ │ real data │
└─────────────┘

Cold cache: Backend → Redis (miss) → DB/API → write Redis → response.

Warm cache: Backend → Redis (hit) → response.

Backend Admin: optional GET cache on proxied admin reads (admin: prefix). Connects via REDIS_URL only (no host/port/password env fallback). Fail-open when unset or unreachable.


LayerRedis
Frontends (Admin, Artists, Finance, Promoters, Venues)No
Backend AdminYes — GET middleware only (REDIS_URL only)
Backends Promoters, MusicData, Finance, Artists, VenuesYes — GET middleware only

  1. GET only — POST/PATCH/PUT/DELETE never use response cache.
  2. Bypass read (still write after handler):
    • Query: ?live=true
    • Header: x-redis: bypass
    • live is stripped from the cache key so bypass and normal requests share one entry.
  3. Cache key: {prefix}:GET:{path}:{sortedQueryHash}:{xOrgOrAnonymous} (GET requests only)
    • Prefix examples: promoters:, musicdata:, finance:, artists:, venues:, admin:
    • x-org header when present; anon when absent.
  4. Mutations (POST/PATCH/PUT/DELETE): purge affected GET keys before the handler runs and again after a successful 2xx (delete only — no write-through). When the write path includes a venue id, Admin and Venues also delete every key matching {prefix}:*{venueId}* plus venue list prefixes (/api/v1/venues, /internal/admin/venues, /api/v1/admin/venues, etc.). Other writes still clear org-wide (x-org), anon, path, collection parent, and cross-route venue aliases where applicable. Deploy Admin and Venues together after venue save fixes.
  5. Response header: X-Cache: HIT | MISS | BYPASS | DISABLED
  6. Startup: fail-open — if Redis is down, backend starts and serves live data.
  7. Skip paths: /health, /ready, /docs, /swagger, /api-docs, MusicData /crontab/*

5. Environment variables (per data backend)

Section titled “5. Environment variables (per data backend)”
VariablePurpose
REDIS_URLConnection string (required for Finance, Admin, Auth, MusicData, and Promoters; preferred elsewhere)
REDIS_HOST, REDIS_PORT, REDIS_PASSWORD, REDIS_DBHost/port fallback on Artists, Venues — not Finance, Admin, Auth, MusicData, or Promoters
REDIS_CACHE_TTL_SECONDSGlobal TTL for that backend
REDIS_CACHE_ENABLED=falseDisable cache (local dev)
BackendDefault REDIS_CACHE_TTL_SECONDS
Finance300 (5 min)
Promoters604800 (7 days)
MusicData604800 (7 days)
Artists604800 (7 days)
Venues604800 (7 days)
Admin604800 (7 days)

When the frontend bypass env is true, the shared API client sends x-redis: bypass on every backend request.

FrontendEnv var
Next.js (Admin, Finance, Promoters)NEXT_PUBLIC_REDIS_BYPASS=true
Vite (Artists, Venues)VITE_REDIS_BYPASS=true

Direct API callers may use ?live=true or x-redis: bypass without frontend env.

Frontends use short React Query staleTime (minutes); long TTL lives on the backend.

x-redis: bypass must propagate on every server-to-server hop until the leaf data backend that owns GET Redis middleware. Each hop:

  1. Detects bypass on the inbound request (x-redis: bypass or ?live=true on GET).
  2. Skips its own Redis read when bypass is active (X-Cache: BYPASS).
  3. Forwards x-redis: bypass on outbound HTTP to other Kisum data backends in the same request context.
sequenceDiagram
  participant FE as Frontend
  participant PR as Promoters
  participant MD as MusicData

  FE->>PR: GET + x-redis: bypass
  Note over PR: X-Cache: BYPASS
  PR->>MD: GET + x-redis: bypass
  Note over MD: X-Cache: BYPASS

Implemented propagation:

ServiceCaptureOutbound
PromotersredisBypassContextMiddleware (AsyncLocalStorage)musicdata.client, artists.client, venues.client, finance-api-client, Auth/Core clients, network proxy controllers
MusicDataredisBypassContextMiddlewaremergeRedisBypassPropagationHeaders helper (leaf for most routes)
FinanceRequest ALS redisBypassauth-service-http, core-service-http
Artists / Venues (Go)redisbypass.CaptureMiddlewareredisbypass.ApplyOutbound on Finance HTTP clients

Auth and Core do not use GET response-cache middleware; forwarding bypass to them is harmless and keeps the chain consistent.


7. Distinct Redis uses (not this middleware)

Section titled “7. Distinct Redis uses (not this middleware)”
ServiceRedis role
AuthSessions, revocation, rate limits — REDIS_URL only (not GET response cache)
CheckoutPending signup / provision state — not HTTP cache

Promoters and Finance must not cache Auth /auth/me/access locally; call Auth live.


  • Repeat GET → second response X-Cache: HIT
  • GET?live=true or x-redis: bypassX-Cache: BYPASS; next normal GET can HIT
  • Frontend NEXT_PUBLIC_REDIS_BYPASS=true / VITE_REDIS_BYPASS=true → browser sends bypass; each hop in §6.1 should also return BYPASS (e.g. Promoters and MusicData on chained artist overview calls)
  • Redis stopped → backend boots; GETs return live data
  • POST/PATCH → no X-Cache header; following GET for the same resource should return fresh data (X-Cache: MISS then warm, or BYPASS when frontend sends bypass)