Skip to content

Add cache validators to embedded static assets - #97

Merged
LarsLaskowski merged 1 commit into
mainfrom
claude/issue-71-h3oqv3
Aug 21, 2026
Merged

Add cache validators to embedded static assets#97
LarsLaskowski merged 1 commit into
mainfrom
claude/issue-71-h3oqv3

Conversation

@LarsLaskowski

@LarsLaskowski LarsLaskowski commented Aug 21, 2026

Copy link
Copy Markdown
Owner

📖 Description

Files served from embed.FS carry a zero ModTime, so http.FileServerFS (internal/web/embed.go) emitted no Last-Modified/ETag, and no Cache-Control header was set — every dashboard page load refetched all static assets, and no intermediary could revalidate a cached copy against anything.

web.Handler now takes the build-time version string (already available as main.version, and echoed by GET /api/v1/config) and wraps the file server to set Cache-Control: no-cache plus a version-derived Etag on every response before handing off to http.FileServerFS. Go's stdlib conditional-request handling (checkPreconditions in net/http/fs.go) picks up an Etag set on the response writer before ServeContent runs, so this is enough for the file server to answer a matching If-None-Match with 304 Not Modified — no extra logic needed. After an upgrade changes version, the ETag changes too, so clients refetch immediately instead of serving stale JS.

This is an internal API change (web.Handler()web.Handler(version string)); the only caller is cmd/pimonitor/main.go, updated to pass version. No REST API shape changes.

🎫 Issues

Closes #71

👩‍💻 Reviewer Notes

Worth double-checking the Etag/Cache-Control behavior directly against the running binary if you want an extra sanity check, e.g.:

curl -i http://localhost:8080/ | grep -i -e etag -e cache-control
curl -i -H 'If-None-Match: "<same-version>"' http://localhost:8080/   # expect 304

📑 Test Plan

Added to internal/web/embed_test.go:

  • TestHandler_SetsCacheHeaders — asserts Cache-Control: no-cache and the version-derived Etag are present.
  • TestHandler_RevalidatesOnMatchingETag — a request with a matching If-None-Match gets 304 Not Modified.
  • TestHandler_RefetchesOnVersionChange — a stale If-None-Match (from a different version) still gets 200 OK.

Existing Handler(...) call sites in embed_test.go updated to pass a version string.

go build ./..., go vet ./..., go test ./... -race -cover, and golangci-lint run all pass locally.

✅ Checklist

General

  • I have added/updated tests for my changes (go test ./... -race -cover passes locally).
  • go vet ./... and golangci-lint run are clean.
  • I have tested my changes.
  • I have read the CONTRIBUTING documentation and followed the project's code style guidelines.
  • I have updated ARCHITECTURE.md if this changes a documented design decision.

REST API / configuration / packaging

Not applicable — no REST API, configuration, or packaging changes.

⏭ Next Steps

None.

Files served from embed.FS carry a zero ModTime, so http.FileServerFS
emitted no Last-Modified/ETag and no Cache-Control, forcing browsers to
refetch every dashboard asset on every page load. Handler now wraps the
file server to set Cache-Control: no-cache plus a version-derived ETag,
so browsers revalidate cheaply (a 304 when the version matches) while
still fetching fresh assets immediately after an upgrade changes the
build version.

Closes #71
@sonarqubecloud

Copy link
Copy Markdown

@LarsLaskowski
LarsLaskowski merged commit 02ab69c into main Aug 21, 2026
5 checks passed
@LarsLaskowski
LarsLaskowski deleted the claude/issue-71-h3oqv3 branch August 21, 2026 17:02
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.

Performance: embedded static assets served with no cache validators or Cache-Control

2 participants