Repository navigation
feat: L2 Cache with Valkey Client Side Hash Ring #4033
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
szuecs
merged 90 commits into
zalando:master
from
larry-dalmeida:feat/cache-client-side-valkey-hash-ring
Sep 2, 2026
+3,102
−218
Merged
Changes from all commits
Commits
Show all changes
90 commits
Select commit
Hold shift + click to select a range
ab6cf2c
feat: add ValkeyStorage with L1 fallback for cache() filter
larry-dalmeida 535836a
feat: split valkey_fallback counter and add valkey_miss metric
larry-dalmeida 0021d81
fix: address WP6 code review feedback
larry-dalmeida f062aa4
feat: add periodic lru_bytes gauge scrape every 10s
larry-dalmeida 716bff8
feat: log storage errors with per-site messages
larry-dalmeida cac6a61
test: must-revalidate forces coalesce when stale
larry-dalmeida 44e1d72
test: unsafe method + 4xx does not invalidate cached entry
larry-dalmeida e8f08ce
test: oversized LRU entry increments lru_oversized and is not stored
larry-dalmeida b64ab9d
test: reval_dropped and L1 fallback write verification
larry-dalmeida 54739d1
feat: tag cache_status, cache_key, cache_ttl_remaining_ms on trace span
larry-dalmeida 08e4865
cache: promote storage Set/Delete error logs from Debug to Warn
larry-dalmeida 78503a7
Promote log to warn
larry-dalmeida eff5cbe
cache: injectable metrics, trace spans, lru_bytes scraper
larry-dalmeida d0d427c
Fix registration of cache filter
larry-dalmeida cd792c3
refactor: add l1TTL field to ValkeyStorage (write-through prep)
larry-dalmeida 61f6d54
feat: write-through L1 warming on successful Valkey Set
larry-dalmeida 1aa06ae
feat: L1-first reads with l1_hit counter in ValkeyStorage.Get
larry-dalmeida a42c47f
fix: update stale counter assertion after L1-first Get, add l1_hit to…
larry-dalmeida d1d7f8d
feat: wire --cache-l1-ttl flag through Options to ValkeyStorage
larry-dalmeida 6e240e7
refactor: move --cache-l1-ttl config field and flag to Valkey section
larry-dalmeida e13b45a
style: use strings.SplitSeq in stripHopByHop and parseVaryNames
larry-dalmeida 12daa1b
fix: add CacheL1TTL to defaultConfig and make Close() synchronous
larry-dalmeida 4eb9e27
style: group cache config fields into dedicated //cache section in co…
larry-dalmeida ecbb64f
style: fix gofmt alignment of bgWg struct field comment
larry-dalmeida d1046bd
fix: address code review findings — vary sentinel invalidation, stub …
larry-dalmeida a0db0e1
docs: document Valkey L2 storage, write-through L1, and cache metrics
larry-dalmeida 25900af
Address PR #4033 code review comments — move goroutines to spec level…
larry-dalmeida e96389e
fix: move SetWithExpire empty-result guard before error loop
larry-dalmeida eac532e
refactor: replace doRevalFn closure with direct filter reference in r…
larry-dalmeida 0093f56
refactor: simplify Options struct comments per code review
larry-dalmeida 9b6527e
fix: replace select-based Close guard with sync.Once to prevent race
larry-dalmeida 7e13db3
feat: add reval_duration histogram metric to revalidation worker
larry-dalmeida 986fa2e
feat: add QUERY method support to cache filter
larry-dalmeida d983c82
docs: clarify cacheFilter.Close no-op intent
larry-dalmeida 6bc5d63
docs: fix forward reference in cacheFilter.Close comment
larry-dalmeida bb16ab5
feat: add filterCacheKey registry to reuse filter instances across ro…
larry-dalmeida c8d34a2
refactor: move filterCacheKey and cacheSpec before NewCacheFilter
larry-dalmeida df17860
feat: add DEL command to ValkeyRingClient
larry-dalmeida fbaa609
fix: add MeasureBackendZone stub to testMetrics
larry-dalmeida fcbeff0
docs: fix Cache section wording in operation.md
larry-dalmeida fa3cdda
docs: explain intentional double L1 lookup on Valkey Get error
larry-dalmeida 1935a7f
docs: clarify thundering herd prevention is process-local in coalesce
larry-dalmeida 6d7a157
fix: prevent send-on-closed panic in enqueueRevalidation and drain ca…
larry-dalmeida f6c4f54
fix: warm L1 on Valkey Get hit using remaining TTL
larry-dalmeida e0f0925
fix: add counter to track warming L1 on Valkey Get hit
larry-dalmeida f86c5ee
feat: add reval_queue_depth and reval_wait_duration metrics
larry-dalmeida 7e41678
fix: handle QUERY body read error in enqueueRevalidation
larry-dalmeida cbaf8b6
fix: update docs/comments to clarify local only DELETE behavior
larry-dalmeida afe76a1
fix: return empty key on QUERY body read failure in cacheKey
larry-dalmeida 956f8e0
fix: add error return to cacheSpec.Close to satisfy io.Closer
larry-dalmeida c7f3fd4
fix: wrap cacheSpec.Close in t.Cleanup and remove extra blank line in…
larry-dalmeida 1afc705
fix: restore CacheL1TTL to Options struct and remove duplicate stale …
larry-dalmeida ce0e84a
refactor: remove cache_key span tag and key param from tagSpan
larry-dalmeida 0b3a382
docs: fix cache key description and add QUERY method support in filte…
larry-dalmeida 3c4818c
docs: expand cache operation docs — metrics, span tags, memory budget…
larry-dalmeida 9046bc3
docs: add inline comments to cache Options fields
larry-dalmeida 76c947d
refactor: replace recover() with context-based shutdown in cache filter
larry-dalmeida 34d00d1
style: gofmt alignment fix in cacheFilter struct after context refactor
larry-dalmeida c8ac0bb
refactor: remove QUERY method support — to be reintroduced in feat/ca…
larry-dalmeida 0d9b8a1
refactor: add cache. prefix to all metrics and route hit/miss/stale/c…
larry-dalmeida 1b7050f
docs: replace SIE acronym with stale-if-error in comments
larry-dalmeida 96602e5
docs: clarify shared L1 cache key semantics and per-user key isolation
larry-dalmeida 5398e72
docs: clarify cache invalidation — no out-of-band API, document avail…
larry-dalmeida bd7825f
docs: clarify process restart only clears L1; Valkey data persists
larry-dalmeida 473696a
docs: clarify coalescing is per-route and document RFC 9111 §3.5 Auth…
larry-dalmeida 61fb35a
refactor: rename metricsScraper to updateMetrics
larry-dalmeida 761e2dc
refactor: remove cacheFilter.Close no-op, io.Closer assertio
larry-dalmeida 2d0defc
fix: treat valkey Get errors as misses instead of falling back to L1
larry-dalmeida 8f53bc0
Merge branch 'master' into feat/cache-client-side-valkey-hash-ring
larry-dalmeida ea96966
fix: update TestCacheFilter_LRUBytesGaugeUpdatesWithoutEviction to pa…
larry-dalmeida 6ae452a
fix: update docs and metrics to reflect valkey Get error handling cha…
larry-dalmeida e99ffd8
fix: rename l1_warm_from_valkey → l2_hit
larry-dalmeida 140f65a
fix: formatting
larry-dalmeida fbde416
fix: don't serve stale L1 entries when Valkey may have fresher copy
larry-dalmeida de56cb8
refactor: use isCacheableMethod on fresh HIT conditional path
larry-dalmeida 44b321f
feat: add cache.storage_error counter at all storage error sites
larry-dalmeida d919e38
docs: document cache.storage_error counter in operation guide
larry-dalmeida b718007
docs: clarify --swarm-valkey-urls wires both ratelimit and cache
larry-dalmeida 923ddc8
add --enable-l2-cache flag to opt in to Valkey as cache L2 backing store
larry-dalmeida d5b283d
rename valkey_miss/get_error/set_fallback metrics to l2_ prefix for c…
larry-dalmeida 3024f17
refactor: cache filter should not know about the implemtnation of L2 …
szuecs ee25732
build: vet was not part of lint target
szuecs ebd6069
refactor: default nil enable sets it
szuecs 91f3bee
refactor: set cache client via options and default to valkey ring cli…
szuecs ee98d3b
fix: test cases should use NewL2.. function
szuecs 18ffb50
test: add more test coverage and integration tests with proxytest tes…
szuecs 5e7f074
ai: adding how to use mockMetrics
szuecs d071612
refactor: rewrite empty interface to any
szuecs 9f7f6ce
add l2_storage coverage
szuecs 840cf86
doc: use PR description to add storage architecture doc
szuecs File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't be there a --cache-l2-ttl also?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Valkey TTL is derived directly from Cache-Control headers:
entry.TTL + max(StaleIfError, StaleWhileRevalidate).There is no separate operator cap because Valkey is the shared cache store and its TTL is the authoritative freshness signal - shortening it would cause unnecessary upstream traffic for clients that would otherwise be served a fresh response.
--cache-l1-ttl existsfor a different reason: L1 is a local in-process optimisation layer, and bounding its TTL prevents a single long-lived response from occupying local memory on every process indefinitely.Note that force mode still holds fully - and it already gives operators exactly what
--cache-l2-ttlwould provide, just at the route level rather than the process level.A
--cache-l2-ttlflag would make sense if there's a concrete operator requirement to cap Valkey retention independently of upstream headers.I've left it out for now to keep the behaviour strictly header-driven, but happy to add it if you have a specific use case in mind.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@a4180p can we resolve this thread?