Recording Response Freshness in Redis Cache
Exposing response freshness with a Redis hot cache, last-success cache, and database fallback
The Hangangjari backend uses Redis to read current values and assembled responses quickly and to find the last successful response when external-source or DB composition fails momentarily.
Cache responses carry source observation time and freshness state. A value read quickly from Redis is still marked stale when its source observation time is old.
Rebuildable Values in Redis
Hangangjari has caches with different purposes.
| Cache | Example | Purpose |
|---|---|---|
| Status cache | Latest parking-lot value | Fast lot-level lookup |
| Forecast cache | Forecast overview/timeline | Reuse computed responses |
| Home summary hot cache | First-screen summary | Fast response with short TTL |
| Home summary stale cache | Last successful summary | Fallback when rebuild fails |
| Source status cache | Source-check result | Reduce repeated lookup cost |
Reference data and history live in Postgres, while Redis stores query results that can be rebuilt.
When Redis is empty, query results are rebuilt from Postgres. Damage to Postgres reference data or history follows the backup recovery procedure.
flowchart LR API["API read"] --> Redis["Redis cache"] Redis -->|Hit| Response["Response"] Redis -->|Miss| Postgres["Postgres rows"] Postgres --> Build["Build payload"] Build --> Redis Build --> Response
Database Fallback for Parking Cache
Parking values are read frequently by lot. The app, widgets, home summary, and forecast inputs all need the latest parking values.
In code, RedisStatusCache owns the current status cache role. It stores JSON payloads by lot ID key. When a cache payload is malformed or Redis is unavailable, the entry is ignored and the query falls back to DB.
The read path applies two rules.
- A cache incident falls back to the database.
- Even a cache hit needs a freshness check.
sequenceDiagram
autonumber
participant Query as Parking query
participant Cache as Status cache
participant DB as Postgres
Query->>Cache: Check parking status cache
alt Cache hit
Cache-->>Query: Return latest parking status
Query->>Query: Judge freshness by source time
else Miss or cache unavailable
Query->>DB: Check last stored status
DB-->>Query: Stored status or none
Query->>Query: Judge stale or empty state
end
Staleness is judged by the time confirmed at the source, not by the time stored in cache. This preserves the same freshness decision regardless of the Redis TTL.
Fast Cache and Last-Success Cache
home-summary is an expensive response to build. It has to gather parking, forecasts, outing data, and source-check results.
Rebuilding the response uses two kinds of cache.
- Hot cache: a short-TTL cache for quickly reusing normal responses.
- Stale cache: a longer-lived backup cache for the last successful payload.
When rebuilding succeeds, both hot and stale cache are updated. If hot cache is empty and rebuilding fails, the stale cache is checked.
flowchart TD
Request["home-summary request"] --> Hot{"Hot cache hit?"}
Hot -->|Yes| ReturnHot["Return hot response"]
Hot -->|No| Rebuild["Rebuild from DB/use cases"]
Rebuild -->|Success| StoreBoth["Store hot + backup cache"]
StoreBoth --> ReturnFresh["Return fresh response"]
Rebuild -->|Failure| Stale{"Backup cache hit?"}
Stale -->|Yes| ReturnStale["Return backup response"]
Stale -->|No| Error["Raise error"]
When stale cache is returned, freshness state and source-check results remain in the payload so the UI marks it as “the last confirmed value.” Fallback is not returned without confirmation time or stale state.
Fewer Repeated HTTP Requests
Server-side Redis cache and HTTP cache have different jobs. A home-summary response receives private cache headers and an ETag. This lets the same app instance get 304 when it repeatedly asks for the same first-screen value in a short period.
The response is treated as private cache because it considers app access conditions and request context.
Response Impact of a Source Change
Hangangjari caches are query outputs rebuilt from source and reference data. Invalidation targets patterns of dependent query results.
When forecasts change, forecast cache and home summary cache are affected. When outing source-check results change, home summary is affected too. The parking value cache is refreshed as the polling job writes the latest snapshots.
Invalidation targets forecast and home-summary responses that depend on the changed source.
Freshness Metadata on Fallback Responses
Redis stores rebuildable query results, and source observation time is checked after every cache hit. Hot cache serves fast responses, while stale cache provides the last successful value after rebuild failure. Cache incidents fall back to the DB and remain in metrics, and stale responses preserve freshness state. HTTP private cache separately reduces repeated requests from the same app instance.
Comments
No comments yet. Be the first to leave one.
Pending review