Skip to content

Stop caching edited pages for a year - #440

Merged
adamjohnwright merged 3 commits into
mainfrom
fix/serve-prod-cache-content
Oct 13, 2026
Merged

adamjohnwright merged 3 commits into
mainfrom
fix/serve-prod-cache-content

Conversation

@adamjohnwright

Copy link
Copy Markdown
Contributor

The bug. beta served every file except index.html as public, max-age=31536000, immutable. That included the documentation and news content, uploads and assets, which keep their names when they change. A browser that had seen a page kept it for a year.

Found when the rewritten Pathway Browser guide (#437), hosted on beta for review, still showed the old page with its Fireworks picture. A hard reload (Ctrl+F5) didn't help: the page's text is fetched by the site's code after the page loads, and a reload doesn't refetch that.

The fix

  • serve-prod.js: only content-named build output stays immutable. That means name-XXXXXXXX.ext at the top of the build or in media/. Everything else is no-cache, so browsers check back and get a 304 when nothing has changed. An upload whose name merely looks hashed isn't trusted.
  • ContentService: requests content files with cache: 'no-cache'. A browser already holding a year-long copy from before then still checks with the server. This is what fixes it for visitors who already have stale copies.

Tests. Both failed before:

  • serve-prod.spec.ts: content-named output is immutable; content, uploads and assets are no-cache.
  • content.service.spec.ts: each of the six content fetches revalidates.

Unit tests: 740 passed.

Deploying. The ContentService half goes live with a beta rebuild. The serve-prod.js half needs the site service restarted: sudo systemctl restart reactome-site.

🤖 Generated with Claude Code

adamjohnwright and others added 3 commits October 13, 2026 17:29
serve-prod sent every file except index.html as `public, max-age=31536000,
immutable`, including the documentation and news content, uploads and
assets, which keep their names when they change. A browser that had seen a
page kept it for a year: the rewritten Pathway Browser guide on beta still
showed the old page, and a hard reload did not help, because the page's text
is fetched by its code after it loads, which a reload does not refetch.

- serve-prod: only content-named build output (name-XXXXXXXX.ext at the top
  of the build or in media/) is immutable; everything else is no-cache, so
  browsers check back and get a 304 when nothing changed. An upload whose
  name merely looks hashed is not trusted.
- ContentService asks for content files with cache: 'no-cache', so a browser
  holding a year-long copy from before still checks with the server.

Tests: serve-prod.spec.ts (content-named output immutable; content, uploads,
assets no-cache) and content.service.spec.ts (each content fetch revalidates);
both failed before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r five minutes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@adamjohnwright

Copy link
Copy Markdown
Contributor Author

Review (subagent, adversarial): no blocking defects. Against a real build listing every esbuild content-named file (8-character base32) matches and nothing unhashed or user-uploaded does; index.html stays no-cache; Angular's fetch backend passes cache through (the app uses withFetch) and nothing calls ContentService in Node. Changes in the latest commit: /site-search-index.json (rebuilt under the same name every build) is fetched with cache: 'no-cache' too; and only .json/.html are now no-cache, while pictures, uploads and other files get public, max-age=300 so they are not refetched on every view but an edit shows within minutes.

Deploy note: images, uploads and assets were served with a one-year max-age, and Cloudflare may hold edge copies under that TTL; changing the origin header does not evict them. If an edited image (same name) still shows old after this is live, purge Cloudflare's cache for /uploads/* and /assets/* (or everything). Content JSON is not on Cloudflare's default cached extensions, so pages themselves are unaffected. Pictures already saved in a browser with the year-long header can't be refreshed from our side; they age out.

@adamjohnwright
adamjohnwright merged commit a0aac6d into main Oct 13, 2026
6 checks passed
@adamjohnwright
adamjohnwright deleted the fix/serve-prod-cache-content branch October 13, 2026 18:04
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