Skip to content

Expand singleflight boundary in ValidatingCache.Get to cover full hit+check and miss+load path#4798

Open
yrobla wants to merge 1 commit intomainfrom
issue-4729
Open

Expand singleflight boundary in ValidatingCache.Get to cover full hit+check and miss+load path#4798
yrobla wants to merge 1 commit intomainfrom
issue-4729

Conversation

@yrobla
Copy link
Copy Markdown
Contributor

@yrobla yrobla commented Apr 14, 2026

Summary

Move the singleflight.Do boundary to wrap the entire Get operation rather than only the miss+load path. This coalesces concurrent liveness checks for the same key into a single storage.Load round-trip, reducing storage pressure under concurrent access.

With only one goroutine running per key at a time, concurrent Gets no longer race with each other. However, concurrent Set calls still happen outside the singleflight boundary, so the miss path retains ContainsOrAdd (not plain Add) to preserve writer-wins semantics: if a Set stores a fresher value while load() is in-flight, that value wins and is returned instead of the loaded one.

Behavior change: an expired cache hit now evicts the entry and falls through to load within the same singleflight operation, returning the fresh value (ok=true) instead of (zero, false). This is a fix: the previous behavior silently dropped a loadable value and forced callers to retry blind.

Fixes #4729

Type of change

  • Bug fix
  • New feature
  • Refactoring (no behavior change)
  • Dependency update
  • Documentation
  • Other (describe):

Test plan

  • Unit tests (task test)
  • E2E tests (task test-e2e)
  • Linting (task lint-fix)
  • Manual testing (describe below)

Changes

File Change

Does this introduce a user-facing change?

Yes — Get on an expired entry now returns the freshly loaded value (ok=true) instead of (zero, false). Callers that were checking ok=false to detect expiry and re-calling Get will now receive the value on the first call.

@yrobla yrobla requested a review from JAORMX as a code owner April 14, 2026 09:43
@yrobla yrobla requested a review from Copilot April 14, 2026 09:44
@github-actions github-actions bot added the size/S Small PR: 100-299 lines changed label Apr 14, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR expands the singleflight boundary in ValidatingCache.Get so that the entire hit+check and miss+load paths are coalesced per key, aiming to reduce duplicate liveness checks / storage round-trips under concurrency.

Changes:

  • Move singleflight.Do to wrap the full Get operation (hit validation + miss load).
  • Simplify the miss-store path by replacing ContainsOrAdd + race-handling with a plain Add, and remove the struct-level onEvict field used for discarded-load cleanup.
  • Update/replace unit tests to reflect new “expired hit falls through to load” behavior and to add a concurrency dedup test.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
pkg/cache/validating_cache.go Wrap full Get in singleflight and simplify the miss store path.
pkg/cache/validating_cache_test.go Update expired-hit expectations and replace a prior race test with a concurrent liveness-check dedup test.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Apr 14, 2026
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 14, 2026

Codecov Report

❌ Patch coverage is 87.50000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.06%. Comparing base (5e1e1d5) to head (c77a110).

Files with missing lines Patch % Lines
pkg/cache/validating_cache.go 87.50% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4798      +/-   ##
==========================================
- Coverage   69.09%   69.06%   -0.03%     
==========================================
  Files         530      530              
  Lines       55191    55202      +11     
==========================================
- Hits        38136    38128       -8     
- Misses      14134    14156      +22     
+ Partials     2921     2918       -3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Apr 14, 2026
@yrobla yrobla requested a review from Copilot April 14, 2026 10:22
@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Apr 14, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Apr 14, 2026
@yrobla yrobla requested a review from Copilot April 14, 2026 13:44
@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Apr 14, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@yrobla yrobla requested a review from jerm-dro April 15, 2026 07:42
@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Apr 15, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Apr 15, 2026
@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Apr 15, 2026
@yrobla yrobla requested a review from Copilot April 15, 2026 07:50
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…+check and miss+load path

Move the singleflight.Do boundary to wrap the entire Get operation rather than
only the miss+load path. This coalesces concurrent liveness checks for the same
key into a single storage.Load round-trip, reducing storage pressure under
concurrent access.

With only one goroutine running per key at a time:
- ContainsOrAdd is replaced with plain Add — the concurrent-writer race between
  multiple Get goroutines no longer exists
- The ContainsOrAdd + Get race-handling block is removed entirely
- The onEvict field on the struct is removed (it was only needed to manually
  call the callback in the discarded-load path)

As a side effect of the new design, an expired cache hit now evicts the entry
and falls through to load within the same singleflight operation, returning the
fresh value instead of (zero, false).

Closes #4729
@yrobla yrobla requested a review from Copilot April 15, 2026 08:06
@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Apr 15, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/S Small PR: 100-299 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expand singleflight boundary in ValidatingCache.Get to cover the full hit+check and miss+load path

3 participants