Check derived store before loading history on content routes #48
No reviewers
Labels
No labels
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: Jinemi/thermograph#48
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/content-store-first"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
The three SEO content handlers in
backend/api/content_routes.py(city / month / records) resolved the city by loading its full ~45-year archive up front, only then checking the derived-store cache. So even a cache HIT paid the full-history load — the 2–6s content-page latency seen on prod.Fix (Fix #2 of 3)
Restructure so the cheap path runs first:
cities.get(slug)-> 404 (dict lookup)grid.snap(lat, lon)(pure, no history)payloads.content_token(cell["id"])— the cheap indexedMAX(date)token from Fix #1, no history loadThe expensive work —
_load_history(cell)(raises 503 while warming), plusclimate.get_recent_forecastfor the city handler — moves into thebuild()closure that_cachedonly invokes on a miss. A store hit, or a 304, now returns replayed bytes without ever touching the archive. Cache keys, kinds, and ETag behavior are unchanged._resolve_city(its only callers were these three handlers) is replaced by_city_cell(cheap) +_load_history(expensive, miss-only).Tests
New
backend/tests/api/test_content_routes.pymirrors theweb/test_api.pyclient pattern with call counters onclimate.load_cached_history/get_historyand a stubbedhistory_max_date. Core regression guard: a first request loads history once, a second identical request is served from the store and loads history zero more times; 304 revalidation loads nothing; plus city/month/records payload shapes and unknown-slug / unknown-month 404s.backend/testsfull suite: 394 passed, 8 skipped.Stacks on #47 (Fix #1,
fix/content-token); this branch is based on it, so review/merge #47 first.Content SEO pages keyed derived-payload cache validity on history_token = PAYLOAD_VER:hist_end, computed from the fully-loaded ~45-year archive. Every hourly tail top-up advanced hist_end and invalidated the whole content cache for a cell, and computing the token at all required loading the full history first — so even cache hits paid the full load. Add content_token(cell_id) = PAYLOAD_VER:CONTENT_VER:max_date, keyed on the archive's newest DATE read cheaply without loading history: climate_store.history_max_date does an indexed MAX(date) over the (cell_id, date) PK on Postgres; climate.history_max_date dispatches to it or to a single-column scan of the cached parquet on the dev backend. The token survives intra-day top-ups and turns over only when the last archived day advances (~1x/day), keeping content pages <=1 day stale. Fail-soft: a store/DB error buckets to 'none' rather than raising. CONTENT_VER ("c1") is a separate content-shape version so a content-only change need not orphan every other kind's cache.