fix(cdn): announce cdn.build_complete from every build trigger - #177
Merged
Conversation
`cdn.build_complete` was emitted by the manual-rebuild endpoint alone, so a push-triggered build refreshed the CDN and told nobody. For a consuming site that is the whole invalidation story: the delivery CDN is a data plane, and a site caching its renders (ISR, durable edge, or a deploy-independent KV like Netlify Blobs) keeps serving pre-build payloads until its TTL lapses. A site redeploy does not help — those caches outlive deploys by design. Observed on staging (Lanista/collabers): every content save produced a correct selective build whose artifacts matched a full rebuild byte for byte, yet the site kept serving pre-save content until someone pressed "Rebuild now". The webhook_deliveries history shows it exactly — ten deliveries, all ten matching a manual build, none for the ~ten push-triggered ones. The rebuild button was doing the purge, not the rebuild. Move the emit into runCDNBuild, which every trigger goes through, so manual, webhook and catch-up builds all announce themselves; catch-up builds move the CDN to a newer commit and need it just as much. The payload shape is unchanged — consumers parse those fields. A clean 0-file no-op (the content-less push short-circuit) stays silent: nothing was published, so nothing needs purging. Failed builds are still announced so the consumer can react.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
cdn.build_completewas emitted from one place — the manual-rebuild endpoint (cdn/builds/trigger.post.ts). The push-triggered path (webhooks/github.post.ts→runCDNBuild) and its catch-up builds never emitted it.That event is not a nicety. For a consuming site it is the entire cache-invalidation story: the delivery CDN is a data plane, and a site that caches its renders (ISR, durable edge cache, or a deploy-independent KV such as Netlify Blobs) keeps serving pre-build payloads until its own TTL lapses. A site redeploy does not fix it — those caches outlive deploys by design, which is exactly what "durable" and "shared blob store" mean.
Evidence (staging — Lanista/collabers)
The CDN itself was never wrong. Git ↔ R2 matched entry-for-entry, and the selective builds produced bundles byte-identical to a full rebuild's (164,616 B across both locales). But the site kept serving pre-save content until someone pressed Rebuild now.
webhook_deliveriesshows why — 10 deliveries, all 10 matching amanualbuild, none for the ~10 push-triggered ones:manualmanualmanualmanualmanualcdn_buildsmirrors it: every content session ends with a manual rebuild. The rebuild button was doing the purge, not the rebuild.Change
Move the emit into
runCDNBuild— the single path every trigger goes through — so manual, webhook and catch-up builds all announce themselves. Catch-up builds move the CDN to a newer commit, so they need it just as much.Tests
4 new runner tests: push-triggered emit, catch-up emit, failed-build emit, no-op silence. The integration test now asserts the endpoint delegates
workspaceIdand does not emit directly.pnpm test1095/1095 ·pnpm lint0 errors ·nuxt typecheckclean.Not in this PR
Two ordering issues found in
executeCDNBuildwhile tracing this, both real but separate:_manifest.jsonis uploaded first and_bundle/*.jsonlast — measured 105 s apart on a full rebuild (R2LastModified11:01:19→11:03:04), ~24 s on a selective one. For that window the CDN advertises a content version it has not published yet._media_manifest.jsonis deleted by the step-7 sweep (it is not inuploadedPathsuntil step 8) and re-uploaded ~1 s later. The SDK throws on non-2xx andMediaAccessorcaches the result for the instance's lifetime, so a lambda booting in that window is poisoned for good.