Skip to content

fix(cache): make TTL.Load context-aware so callers can cancel while waiting#54

Open
jpugliesi wants to merge 7 commits into
mainfrom
john/ttl-load-context-cancellation
Open

fix(cache): make TTL.Load context-aware so callers can cancel while waiting#54
jpugliesi wants to merge 7 commits into
mainfrom
john/ttl-load-context-cancellation

Conversation

@jpugliesi

Copy link
Copy Markdown
Contributor

Summary

  • TTL.Load blocked on <-promise.ready with no way to interrupt the wait, so a caller whose context was canceled had to wait for the shared in-flight fetch to complete before receiving an error
  • Replace the plain channel receive with select { case <-promise.ready: ...; case <-ctx.Done(): ... }
  • Cancellation returns context.Cause(ctx) immediately; the in-flight goroutine continues to completion and stores the result for future callers — no goroutine leak, no cache poisoning
  • Updated all TTL.Load call sites (cache.go, secret/cache.go, secret/authn/cache.go) to pass ctx as the new first parameter

Test plan

  • go test ./cache/... passes, including new TestTTLLoadContextCancellation which verifies a co-waiter with a canceled context returns promptly while the fetch completes and is stored in cache

🤖 Generated with Claude Code

…aiting

The previous implementation blocked on <-promise.ready with no way to
interrupt the wait. When multiple callers share an in-flight singleflight
promise, a caller whose context is canceled had to wait for the fetch to
complete before receiving an error.

Replace the plain channel receive with a select over promise.ready and
ctx.Done(). On cancellation the caller returns context.Cause(ctx)
immediately; the in-flight goroutine continues to completion and stores
the result in cache for future callers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@jpugliesi jpugliesi force-pushed the john/ttl-load-context-cancellation branch from f367776 to 365a6de Compare April 3, 2026 19:15
jpugliesi and others added 2 commits April 3, 2026 12:35
- Bail out early (under the lock) if the caller's context is already
  canceled before starting a new fetch, preventing timed-out callers
  from triggering background provider I/O.
- Use a double-select when ctx.Done() wins the race so a completed
  shared result is preferred over a simultaneous cancellation, avoiding
  flaky errors for co-waiters near their deadline.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- TestTTLLoadAlreadyCanceledCacheMiss: verifies that Load with a
  pre-canceled context on a cache miss returns immediately without
  invoking fetch or populating the cache.
- TestTTLLoadReadyBeatsCancel: stress-tests (1000 iterations, -race)
  the double-select by unblocking the fetch and canceling the co-waiter
  simultaneously, ensuring the only outcomes are success or
  context.Canceled and no other error is returned.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread cache/ttl.go Outdated
Comment thread cache/lru_test.go
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