Skip to content

🧹 chore: refactor cache handler lock flow#4492

Open
Rachit-Gandhi wants to merge 12 commits into
gofiber:mainfrom
Rachit-Gandhi:fix/issue4334-refactor-cache-lock
Open

🧹 chore: refactor cache handler lock flow#4492
Rachit-Gandhi wants to merge 12 commits into
gofiber:mainfrom
Rachit-Gandhi:fix/issue4334-refactor-cache-lock

Conversation

@Rachit-Gandhi

@Rachit-Gandhi Rachit-Gandhi commented Jul 2, 2026

Copy link
Copy Markdown

Summary

  • Replace the cache handler's local lock-state closures with a scoped lock guard.
  • Remove goto continueRequest by making the cache lookup phase return an explicit handled/error result.
  • Deduplicate cached-entry delete/remove flow so storage deletion happens outside the lock and heap/accounting updates happen under the lock.
  • Use the same lock helper in the store and eviction sections, and switch the mutex to sync.Mutex because no read-lock paths are used.

Closes #4334.

Validation

Manual validation run locally because the PR checks currently only show labeler/Dependabot jobs:

  • make lint -> 0 issues.
  • go test ./middleware/cache -race -count=1 -> passed
  • go test ./middleware/cache -run Test_Cache_RevalidationUncacheableResponseDeletesStaleEntry -count=1 -> passed
  • go test ./middleware/cache -coverprofile=/tmp/fiber-cache-cover.out -count=1 -> passed, coverage: 92.0% of statements
  • make test -> DONE 3917 tests, 2 skipped in 54.602s

guards
Refactor lock management so scope is defer-bounded and unlocks can't be
missed:
- Add cacheLockGuard with a withCacheLock(mux, fn) helper that acquires
  the lock and releases it via defer, replacing every raw
  mux.Lock()/Unlock() pair in the read, store, and eviction sections.
- Extract deleteCurrentEntry(), which encapsulates the unlock ->
  deleteKey -> relock -> removeHeapEntry sequence in one place instead
  of repeating it at three read-path branches and the post-response
  deletion.
- Replace `goto continueRequest` with an anonymous func returning
  (handled bool, err error) so control flow is explicit.
- Convert the eviction loop's mid-loop `mux.Unlock(); return` to setting
  an error and returning from the withCacheLock closure, so the lock is
  always released.
- Narrow mux from sync.RWMutex to sync.Mutex, since only exclusive
  locking is ever used.
@welcome

welcome Bot commented Jul 2, 2026

Copy link
Copy Markdown

Thanks for opening this pull request! 🎉 Please check out our contributing guidelines. If you need help or want to chat with us, join us on Discord https://gofiber.io/discord

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Refactors cache middleware locking and request handling, updates invalidation and eviction flows, and adjusts expiration bookkeeping in the cache path.

Changes

Cache lock refactor

Layer / File(s) Summary
Lock guard primitives and mutex type change
middleware/cache/cache.go
Adds cacheLockGuard and withCacheLock, and switches the cache mutex type to *sync.Mutex.
Cache request handling
middleware/cache/cache.go, middleware/cache/cache_test.go
Reworks handledCacheRequest, adds deleteCurrentEntry, changes unlock/relock timing around cached bodies and raw-body loading, and adds an only-if-cached auth-entry test.
Post-response invalidation and revalidation
middleware/cache/cache.go, middleware/cache/cache_test.go
Routes active-entry invalidation through deleteCurrentEntry(nil, ...), uses deleteRevalidatedEntry for cleanup, and adds tests for private replacement, stale-entry deletion, and concurrent revalidation replacement handling.
Eviction and rollback locking
middleware/cache/cache.go
Wraps reservation, eviction candidate handling, rollback, and heap restoration on deletion failure with withCacheLock.
Timestamp and store-path bookkeeping
middleware/cache/cache.go
Introduces storeTS, adjusts expiration handling, and wraps heap insertion, cleanup, and old-entry removal with withCacheLock.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • gofiber/fiber#3989: Both change middleware/cache/cache.go around cache-control decisions, authorization/vary handling, and heap/eviction bookkeeping.
  • gofiber/fiber#4419: Both modify cache lock and timestamp handling used for freshness decisions.
  • gofiber/fiber#3905: Both touch cache-entry shareability and authorization-based caching behavior.

Suggested reviewers: sixcolors, efectn, ReneWerner87

Poem

A bunny hopped through cache and time,
With guarded paws and tidy rhyme.
Old entries poofed, fresh ones shone,
The heap stayed neat, the lock held strong.
🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is useful, but it does not follow the repository's required template or include the requested sections. Add the required Description template sections, including Fixes #, Changes introduced, Type of change, and the checklist items.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: refactoring the cache handler lock flow.
Linked Issues check ✅ Passed The refactor matches #4334 by replacing the goto-based lock flow with scoped lock handling and clearer unlock/relock boundaries.
Out of Scope Changes check ✅ Passed The additional test coverage and cache deletion adjustments are directly related to the lock-flow refactor and cache correctness.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ReneWerner87 ReneWerner87 added this to v3 Jul 2, 2026
@ReneWerner87 ReneWerner87 added this to the v3 milestone Jul 2, 2026
@Rachit-Gandhi Rachit-Gandhi marked this pull request as ready for review July 2, 2026 01:43
@Rachit-Gandhi Rachit-Gandhi requested a review from a team as a code owner July 2, 2026 01:43

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@middleware/cache/cache.go`:
- Around line 346-352: The revalidation flow in cache handling drops e after
releasing the old entry, but later cleanup only runs through deleteCurrentEntry
when e is still non-nil. Update the revalidation paths in cache.go so the code
that handles reqDirectives/maxAge and the response handling for private,
no-cache, and Vary:* preserves whether there was a prior cached entry and its
oldHeapIdx separately from e, then explicitly delete the key and remove the old
heap entry even when e has been cleared. Use the existing
revalidation/deleteCurrentEntry logic as the place to wire in this cleanup in
the affected branches.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d6e26a0f-cf21-4b90-bb8a-c95662184f78

📥 Commits

Reviewing files that changed from the base of the PR and between 05919e5 and a887f89.

📒 Files selected for processing (1)
  • middleware/cache/cache.go

Comment thread middleware/cache/cache.go Outdated
@codecov

codecov Bot commented Jul 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.96567% with 56 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.01%. Comparing base (adef0e8) to head (08fcaca).

Files with missing lines Patch % Lines
middleware/cache/cache.go 75.96% 45 Missing and 11 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4492      +/-   ##
==========================================
- Coverage   93.01%   93.01%   -0.01%     
==========================================
  Files         139      139              
  Lines       13789    13816      +27     
==========================================
+ Hits        12826    12851      +25     
  Misses        596      596              
- Partials      367      369       +2     
Flag Coverage Δ
unittests 93.01% <75.96%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 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.

@pageton

pageton commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Summary

Reviewed the full diff, traced every lock acquire/release path, and verified locally:

  • go vet ./middleware/cache/ — clean
  • go test ./middleware/cache/ -race -count=1 — all pass
  • ✅ Confirmed zero RLock/RUnlock usage — the RWMutexMutex change is safe

No critical issues

The refactoring is well-executed:

  • cacheLockGuard with idempotent unlock()/relock() is a strict improvement over the ad-hoc locked/unlock/relock closures.
  • IIFE replacing goto continueRequest — clean. ts is correctly scoped inside the closure; the store phase uses storeTS.
  • deleteCurrentEntry helper — deduplication is correct. The closure captures e by reference; the order (remove heap entry → release pool entry) is safe since removeHeapEntry reads e.heapidx before release zeroes it.
  • withCacheLock in the store/eviction phase — consistent guard + defer pattern throughout.

Bug fix in commit 2 — real correctness improvement

The case revalidate: branch fixes a pre-existing bug in main:

When revalidation sets e = nil (e.g., client sends max-age=0) and the refreshed response comes back private, no-cache, or Vary: *, the old cached entry was orphaned because cleanup was gated solely on e != nil. The stale entry persisted in storage and the heap for its full original TTL, being served as cache hits to subsequent clients despite the origin explicitly marking the response uncacheable.

This is a correctness issue (RFC 9111 violation), not performance or safety:

  • Not performance — the stale entry is served as a cache hit (fewer origin calls, not more)
  • Not safety — the stale data was already public/cacheable; no new sensitive data is leaked
  • Self-healing via TTL expiry, but the stale window can be the full original TTL

Minor notes (non-blocking)

  1. Redundant guard: cfg.Storage != nil in deleteCurrentEntry before manager.release(e) is redundant — release() already early-returns when storage == nil. Harmless, just dead defensive code.

  2. Test coverage: Patch coverage is ~73% with 60 uncovered lines, concentrated in the new error-handling branches. The revalidation + uncacheable-response fix would especially benefit from a dedicated test — it's a correctness-critical path.

  3. CI: No Go test/lint check runs are visible in the PR checks yet (only labeler/Dependabot). Ensure CI gates the merge.

Verdict

Approve. The refactoring is sound, and the included bug fix is a genuine correctness improvement worth merging on its own merit.

@Rachit-Gandhi

Copy link
Copy Markdown
Author

@pageton thanks for the detailed review, I will work through the addressable notes with specific tests for the lines, removal of redundant guard and make ci checks validation as part of the PR summary.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Refactors the cache middleware handler’s lock/unlock control flow to remove goto-based paths, centralize lock handling via a guard helper, and simplify deletion/eviction bookkeeping by moving storage I/O outside the lock while keeping heap/accounting updates under lock.

Changes:

  • Introduces a cacheLockGuard + withCacheLock helper and switches the handler mutex from sync.RWMutex to sync.Mutex.
  • Refactors the cache-lookup phase to return an explicit (handled, error) result instead of using goto continueRequest.
  • Deduplicates cached-entry deletion and restructures eviction space reservation/restoration under a single lock helper.

Comment thread middleware/cache/cache.go
Comment thread middleware/cache/cache.go Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 08fcaca7b3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread middleware/cache/cache.go Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4f449140ef

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread middleware/cache/cache.go Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 26121f8194

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread middleware/cache/cache.go Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a4c051f84a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread middleware/cache/cache.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

🧹 [Maintenance]: refactor cache handler lock management — replace goto/unlock/relock pattern

5 participants