fix(ci): prerender the web bundle after the api/worker deploy, not beside it
Some checks failed
deploy / Build api + worker (static musl) (push) Waiting to run
deploy / Build prerendered web (push) Has been cancelled
deploy / Deploy moments-api to nikola (push) Has been cancelled
deploy / Deploy moments-worker to frootmig (push) Has been cancelled
deploy / Deploy web to oolon (push) Has been cancelled
Some checks failed
deploy / Build api + worker (static musl) (push) Waiting to run
deploy / Build prerendered web (push) Has been cancelled
deploy / Deploy moments-api to nikola (push) Has been cancelled
deploy / Deploy moments-worker to frootmig (push) Has been cancelled
deploy / Deploy web to oolon (push) Has been cancelled
`build-web` had no `needs:`, so it ran in parallel with the binary build and both deploy jobs. The prerender fetches VITE_API_BASE at build time, which means the job baked whatever the api happened to be serving at the moment it ran — old binary or new, depending on which runner finished first. Both outcomes showed up on consecutive runs. Run 68 won by ~25 seconds and the repo-visibility fix reached the api and the crawler snapshot together. Run 69 lost: the api served the new activity/summary private aggregate while the baked /activity/ snapshot had none, so the 15 August card read "47 changes in 3 repositories" where the api said 54 with 7 private. Browsers hydrate and refetch, so a visitor saw the right page — but curl, which is what crawlers and AI screeners get, saw the stale one until refresh.yml was dispatched by hand. Nothing in the pipeline noticed. deploy-worker is in the needs list alongside deploy-api because the worker owns migrations: a schema change isn't live until it has restarted, so an api that depends on one isn't answering correctly before then either. The graph is now serial — binaries -> api/worker -> web — which costs the overlap between the web build and the binary build. Worth it: the alternative is a published snapshot whose correctness depends on runner scheduling, failing silently and for a whole day. Job graph verified acyclic with every `needs:` resolving to a real job. Closes #8
This commit is contained in:
@@ -101,6 +101,19 @@ jobs:
|
||||
|
||||
build-web:
|
||||
name: Build prerendered web
|
||||
# The prerender fetches VITE_API_BASE at build time, so this job bakes
|
||||
# whatever the api is serving when it runs. Without these dependencies it
|
||||
# raced the api/worker deploys and the crawler snapshot silently disagreed
|
||||
# with the live api for a whole day, until the nightly refresh: it won the
|
||||
# race once (a visibility fix reached both together) and lost it once (an
|
||||
# api field the snapshot then lacked). deploy-worker is in the list too,
|
||||
# not just deploy-api — the worker owns migrations, so a schema change
|
||||
# isn't applied until it has restarted.
|
||||
#
|
||||
# The cost is a serial deploy: binaries -> api/worker -> web. Worth it;
|
||||
# the alternative is a snapshot whose correctness depends on which runner
|
||||
# finished first.
|
||||
needs: [deploy-api, deploy-worker]
|
||||
runs-on: fedora-44
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -119,6 +119,13 @@ CI-driven via **Gitea Actions** (`.gitea/workflows/`), the source of infra truth
|
||||
prerendered web bundle, then deploy each component over SSH as the `gitea_ci`
|
||||
user with scoped sudo (`asset/sudoers.d/`). Services run under systemd with
|
||||
hardened units; the api/worker reach postgres over mTLS using the host cert.
|
||||
The job graph is deliberately serial — binaries → api/worker → web — because
|
||||
the prerender fetches `VITE_API_BASE` at build time and so bakes whatever the
|
||||
api is serving when `build-web` runs. `build-web` therefore `needs:` both
|
||||
deploy jobs (the worker owns migrations, so a schema change isn't live until
|
||||
it restarts). When it ran in parallel instead, whether the crawler snapshot
|
||||
matched the api came down to which runner finished first, and a lost race
|
||||
meant a stale snapshot until the nightly refresh.
|
||||
- `refresh.yml` — daily `schedule:` (+ manual): rebuilds and redeploys only the
|
||||
web tier, re-baking the prerendered crawler snapshot from the current gist (CV)
|
||||
and activity API without bouncing the api/worker.
|
||||
|
||||
Reference in New Issue
Block a user