Skip to content

gallery: read the version the store holds, and write it conditionally - #8

Merged
azank1 merged 2 commits into
mainfrom
fix/gallery-versions
Oct 13, 2026
Merged

azank1 merged 2 commits into
mainfrom
fix/gallery-versions

Conversation

@azank1

@azank1 azank1 commented Oct 13, 2026

Copy link
Copy Markdown
Owner

What's wrong

The homepage dashboard draws from gallery/recent.json, which every build rewrites. In production right now:

/api/gallery says the store and the city say
vercel (latest built) 14,661 commits 19,089
sindresorhus 2,696 2,826

The Blob CDN keeps serving an overwritten blob long after its 60 s max-age (a copy aged 194 s was a HIT, and /api/gallery was still answering 14,661 more than 15 minutes after the overwrite). The store's "fresh" read appends a ?fresh= query string, which the CDN ignores. So a build that read a stale copy and wrote it back also undid the build before it: sindresorhus's 11:01 entry was lost to vercel's 11:02 write.

Fix

  • Each version is also written to gallery/recent/<id>.json. Those blobs are never overwritten, so any CDN copy of them is correct.
  • gallery/recent.json carries the current id in its content type, application/json; version=<id>. A head request reads it from the store, not the CDN. The list also stays in the body, for readers from before this change.
  • Writes are conditional on its etag (ifMatch) and retry with backoff, so builds that finish together all get in.
  • A featured city takes its entry from the list when it's there, so the featured and "latest built" tiles always show the same build.

Cost (Hobby quota)

  • Per build: one head (a simple op) and one extra put.
  • Per gallery read: one head, under the endpoint's 60 s edge cache.

#4 covers the same ground with a list per read, which the 2,000 advanced ops a month can't carry. This handles the gallery half of #4 without one.

Tests

  • A new test store mimics production: reads of an overwritten blob return the first copy ever written, while stat and conditional writes see the store itself. Against it:
    • five builds finishing together all reach the gallery
    • a rebuilt city moves to the front once, with its new numbers
    • hiding an owner removes their cities
    • an old-format list is read and carried into the first version
  • web: 42 tests, 36 pass, 6 live tests skipped. Typecheck is clean.

After merge

Check that the store keeps the content type's version parameter: the blob's public URL returns content-type as stored. If the store dropped it, reads would fall back to today's behaviour.

The landing page's dashboard draws from gallery/recent.json, rewritten by
every build. The blob CDN serves an overwritten blob long past its 60 s
max-age: /api/gallery kept answering vercel at 14,661 commits for more
than 15 minutes after the rebuild that put it at 19,089 was stored, and
the build that read a stale copy and wrote it back undid the build before
it (sindresorhus is stored at an older 2,696; its city is 2,826). The
"fresh" read appends a query string, which the CDN ignores.

- Each version is also written to gallery/recent/<id>.json, never
  overwritten, so any CDN copy of it is the right one.
- gallery/recent.json carries the current id in its content type; a head
  request reads that from the store, not the CDN. The list stays in its
  body too, for readers from before this change.
- Writes are conditional on its etag (ifMatch) and retry with backoff, so
  builds that finish together all get in.
- Featured cities take their entry from the list when they are in it, so
  the featured and latest-built tiles show the same build.

Cost per build: one head (simple op) and one more put; per gallery read,
one head. #4 covers the same ground with a list per read, which the Hobby
quota cannot carry; this handles the gallery half of it without one.
@vercel

vercel Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
commit-city Ready Ready Preview Oct 13, 2026 11:58am UTC

facebook/react moved to react/react, and the landing page showed both: a
featured react/react tile with 685 commits (a city built under the old
name on 2026-10-11) and a latest-built one with 689 (built under the new
name a day later), the first opening the second. Featured now names
react/react, and entries kept under a repo's old name stay off the lists.
@azank1
azank1 marked this pull request as ready for review October 13, 2026 12:22
@azank1
azank1 merged commit 7e77f41 into main Oct 13, 2026
5 checks passed

This branch was successfully deployed

1 active deployment
Preview — e3eb99cb Deployed Oct 13, 2026 by vercel[bot]
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