Skip to content

Add read-only mode to allow cache reads but skip writes#9

Merged
richardartoul merged 4 commits intorichardartoul:mainfrom
cchristous:cchristous/read-only-mode
Feb 18, 2026
Merged

Add read-only mode to allow cache reads but skip writes#9
richardartoul merged 4 commits intorichardartoul:mainfrom
cchristous:cchristous/read-only-mode

Conversation

@cchristous
Copy link
Contributor

Summary

  • Adds -read-only flag and GOBUILDCACHE_READ_ONLY environment variable to enable read-only mode
  • When enabled, cache reads (GETs) work normally but writes (PUTs) are skipped and return success
  • Useful for feature branches that should pull from cache but not pollute the shared cache

Changes

  • main.go: Added flag, env var support, help text, and startup info message
  • server.go: Added readOnly field, skippedPuts counter, skip logic in handlePut, and fixed pre-existing division-by-zero bugs in stats output when getCount or putCount is zero
  • server_test.go: Added unit tests for read-only mode behavior
  • README.md: Added configuration table entry

Test plan

  • Unit tests pass (go test ./...)
  • Integration tests pass (excluding S3 which requires credentials)
  • Manual testing with GOBUILDCACHE_READ_ONLY=true to verify PUTs are skipped

This enables use cases where you want to pull from the cache but not
populate it, such as running tests on feature branches without
polluting the shared cache.

- Add -read-only flag and GOBUILDCACHE_READ_ONLY env var
- Skip PUT operations when enabled, returning success without writing
- Add skippedPuts counter to stats output
- Fix division-by-zero in stats when getCount or putCount is zero
- Add unit tests for read-only mode behavior
@cchristous cchristous marked this pull request as ready for review February 7, 2026 20:37
server.go Outdated
duplicateGets, float64(duplicateGets)/float64(getCount)*100)
fmt.Fprintf(os.Stderr, " Deduplicated GETs (singleflight): %d (%.1f%% of GETs)\n",
deduplicatedGets, float64(deduplicatedGets)/float64(getCount)*100)
if getCount > 0 {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you remove this conditional so the output is uniform?

Copy link
Contributor Author

@cchristous cchristous Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the conditionals entirely. Stats lines are now always printed with inline division, matching the original code style.

server.go Outdated
if skippedPuts > 0 {
fmt.Fprintf(os.Stderr, " Skipped PUTs (read-only mode): %d\n", skippedPuts)
}
if putCount > 0 {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

Copy link
Contributor Author

@cchristous cchristous Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same — removed the putCount > 0 conditional as well.

@cchristous cchristous closed this Feb 18, 2026
@cchristous cchristous deleted the cchristous/read-only-mode branch February 18, 2026 13:31
@cchristous cchristous restored the cchristous/read-only-mode branch February 18, 2026 18:31
Pre-compute percentage rates with division-by-zero guards instead
of conditionally omitting the stats lines when counts are zero.
@cchristous cchristous reopened this Feb 18, 2026
server.go Outdated
resp.ID = req.ID

// In read-only mode, skip all writes but return success
if cp.readOnly {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you might be terminating too early. If you do this, then the program won't even write to the local cache and you'll keep recompiling the same stuff over and over locally. I think what you want is to still write locally, but not write back to the object store right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — moved the read-only check to after the local cache write so local builds still benefit from disk cache. Only the backend PUT is skipped now.

Previously, read-only mode returned early in handlePut, skipping both
the local disk cache and backend writes. This meant local builds would
recompile the same artifacts repeatedly since nothing was cached locally.

Now the read-only check happens after the local cache write but before
the backend PUT, so local builds still benefit from the disk cache while
the shared remote cache is not polluted with feature branch artifacts.
@richardartoul richardartoul merged commit c9c22f2 into richardartoul:main Feb 18, 2026
1 check failed
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.

2 participants