Skip to content

[01] Bucket-first serving: versioned, atomic, edge-cacheable blobs - #18

Open
chondl wants to merge 8 commits into
cph-masterfrom
cph-bucket-first-serving
Open

[01] Bucket-first serving: versioned, atomic, edge-cacheable blobs#18
chondl wants to merge 8 commits into
cph-masterfrom
cph-bucket-first-serving

Conversation

@chondl

@chondl chondl commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Replacement for #2, which GitHub auto-closed when its head branch was renamed bucket-first-serving -> cph-bucket-first-serving. Same commits; base is now cph-master. Part of the cph-staging series.

chondl added 8 commits July 9, 2026 21:59
Pull the /team/{num} and /team/{num}/{year} payload shaping out of the
route bodies into reusable helpers (verified byte-identical responses)
so the blob export and historical backfill can produce payloads
identical to the API. Adds the HIST_EPOCH constant that versions the
immutable historical blob path.
write_objs now renders the current-year blob set, uploads only blobs
whose content hash changed (copy-on-write, to immutable content-addressed
v2/{path}.{hash} keys with long-lived Cache-Control), and writes
manifest.json last so readers always resolve a complete old or new set,
never a torn mix. Adds a team/{num} blob per active team. Legacy
unversioned paths are still written each cycle for compatibility with
the deployed frontend. The lossy str(Event) upload gate is replaced by
the content hash, which also stops event blobs going stale between
match updates.
One-time script exporting team_years/{year}, events/{year}, event/{key}
and team/{num}/{year} for every past season (2021 skipped) to the
immutable hist/{HIST_EPOCH} path, using the shared site _read_* helpers.
Idempotent per object and resumable via a bucket-side progress
checkpoint.
Blob URLs now resolve through manifest.json: immutable versioned URLs
for the current-year set, epoch-prefixed paths for historical years,
with no per-request cache-buster. When no manifest exists (backend not
yet deployed) fetches fall back to the legacy path plus ?t= buster, and
the backend keeps writing legacy paths, so either deploy order works.
getTeam, getYearTeamYears, and historical getTeamYear become
bucket-first; the two team-match fetches read the event blob and
team-year payload instead of API-only endpoints. Expired IndexedDB
entries are retained and served as a last resort when both bucket and
API fail, instead of rendering an empty page.
F1/F2: the event blob embeds the full year object, whose stats churn every
in-season cycle, so content-addressing re-uploaded all ~215 event blobs each
cycle (defeating the immutable edge cache). Render an event blob only when its
own event/match/team_event content changes (NaN-stable comparison); unchanged
events carry forward their prior versioned key and stale year snapshot.
…params

A7: a single failed manifest.json fetch no longer pins every client to the
uncached legacy ?t= path for a full 60s TTL (a null result is dropped from the
cache so the next call retries). toLogicalPath now replaces all ? and & so blob
keys with 3+ query params resolve instead of missing to the backend.
… wave

- getMatch: derive the match view from the (bucket-first, edge-cached) event
  blob — the match key encodes its event, and the event blob already carries the
  match + its team_matches + team_events. Falls back to the /match API when the
  blob lacks the match. Removes the Cloud-Run round trip (and its cold-start
  tail) from the match page's critical path.
- getTeamYear: start the event-blob fetches as soon as team_to_events resolves
  instead of gating them on the whole metadata Promise.all, which included the
  large team_years/{year} blob the event wave does not need.
The not-found placeholder waited 8000ms before rendering, leaving a blank
content area for 8 full seconds on any nonexistent or slow-to-load entity
(/team/99999, /event/2026zzzzz, etc.). The debounce exists only to avoid a
flash of the not-found message before data arrives; 1.5s is ample for that
while no longer looking like a hung page. (The comment already described the
intent as 'one second'; the 8000 value grew from 1000 over prior commits.)
@chondl chondl changed the title [blob-store 1/5] Bucket-first serving: versioned, atomic, edge-cacheable blobs [01] Bucket-first serving: versioned, atomic, edge-cacheable blobs Jul 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant