Skip to content

perf(website): cache certificate images between deploys (~25 min → ~4 min) - #1281

Merged
felipesalinasr merged 2 commits into
mainfrom
fix/website-deploy-cert-cache
Aug 10, 2026
Merged

perf(website): cache certificate images between deploys (~25 min → ~4 min)#1281
felipesalinasr merged 2 commits into
mainfrom
fix/website-deploy-cert-cache

Conversation

@felipesalinasr

Copy link
Copy Markdown
Collaborator

Before merging — one manual step

Neither of Felipe's stored tokens carries the workflow scope, so this PR currently contains only the code half. The workflow edit below must be added from an account/token with workflow scope (edit .github/workflows/website-deploy.yml in the web UI on this branch, or push after gh auth login with the workflow scope). Insert this step between "Fail if POSTHOG_KEY is missing" and "Build site":

      # Certificate images are expensive: every issued certificate is two big
      # satori + resvg canvases, and without this cache a fresh runner re-draws
      # the whole cohort on every deploy (~20 min of the run). The digest
      # manifest (website/.cache) decides staleness per attendee, but the skip
      # also requires the previously rendered PNGs to exist in _site/c, so both
      # are cached. The key is per-run so the post-job save always records the
      # latest state; restore falls back to the most recent previous deploy.
      # Correctness lives in the manifest digests (attendee data + renderer
      # fingerprint), and render.mjs prunes images for certificates that are no
      # longer issued, so a stale cache can never ship a wrong or revoked image.
      - name: Restore certificate image cache
        uses: actions/cache@v4
        with:
          path: |
            website/.cache
            website/_site/c
          key: cert-images-${{ github.run_id }}
          restore-keys: |
            cert-images-

Why

Every website deploy takes 21–30 minutes (last four: 27.0, 26.7, 29.6, 21.2). Almost all of it is the certificate image renderer: two large satori+resvg canvases per issued certificate, re-drawn from scratch every deploy because neither the digest manifest (website/.cache) nor the rendered PNGs (_site/c) survive between CI runs — only npm is cached.

What

  1. Workflow (the block above): cache website/.cache + website/_site/c across runs. Per-run key + prefix restore-keys, so the post-job save always records the newest state and the next run restores the most recent one.
  2. Code (in this PR): pruneStaleImages in lib/certs/image-cache.mjs, called after each render pass. With _site/c now persisted, images for certificates that are no longer issued would otherwise ride the cache forever; the prune deletes them. Correctness of content was already handled by the digest manifest (attendee data + renderer fingerprint), which is unchanged. The prune is safe to land before the workflow change (on a clean _site it is a no-op).
  3. Tests: website/test/cert-image-prune.test.mjs (4 cases: stale pair deleted, current + non-PNG kept, dotted codes, missing dir no-op).

Verified

  • npm test: 11/11 pass. Clean Eleventy build. Biome clean.

Expected effect: website deploys drop from ~25 min to ~3–4 min when few certificates changed; a renderer/template change still re-renders everything (fingerprint in the digest), which is correct.

🤖 Generated with Claude Code

felipesalinasr and others added 2 commits August 9, 2026 11:32
Groundwork for caching _site/c between CI deploys: images for
certificates that are no longer issued are deleted after each render
pass, so a restored cache can never ship a revoked credential. Unit
tests cover the prune.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Restore website/.cache (digest manifest) and website/_site/c (rendered
PNGs) before the build, per-run key with prefix restore, so only new or
changed certificates re-render. Pairs with the pruneStaleImages pass so
a restored cache can never ship a revoked credential.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@felipesalinasr
felipesalinasr merged commit 2d9754a into main Aug 10, 2026
23 of 24 checks passed
@felipesalinasr
felipesalinasr deleted the fix/website-deploy-cert-cache branch August 10, 2026 16:24
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