Skip to content

[4.x] Make globalCache always use the central connection with database cache store#1462

Open
lukinovec wants to merge 4 commits into
masterfrom
fix-cache-invalidation
Open

[4.x] Make globalCache always use the central connection with database cache store#1462
lukinovec wants to merge 4 commits into
masterfrom
fix-cache-invalidation

Conversation

@lukinovec
Copy link
Copy Markdown
Contributor

@lukinovec lukinovec commented Jun 1, 2026

globalCache should always use the central connection, but when using a database-driver cache store with DatabaseTenancyBootstrapper, it does not (with the exception of DatabaseCacheBootstrapper, explained below).

globalCache creates a fresh CacheManager each time it's resolved (it's a bind, not a singleton). A freshly-created manager builds its database stores using the current default DB connection. When DatabaseTenancyBootstrapper is active, that default is tenant. So globalCache in tenant context points at the tenant DB. Specifically, CachedTenantResolver stores cached tenant lookups via globalCache. When a domain is deleted in tenant context, the invalidation logic calls globalCache->forget(...), but that hits the tenant DB, while the resolver cache entry is in the central DB. globalCache->forget(...) doesn't actually do anything in that case.

With DatabaseCacheBootstrapper, this is already handled. globalCache is always central because it sets TenancyServiceProvider::$adjustCacheManagerUsing to a callback that explicitly restores the central connection on globalCache's stores.

To fix this, after constructing the fresh CacheManager in the globalCache binding, explicitly set the connection of every database-driver store to its configured connection value, falling back to central_connection when the config value is null (null value = inherits whatever the current default DB connection is).

This is sufficient for CacheTenancyBootstrapper and any other bootstrapper that doesn't explicitly set the store's DB connection. For DatabaseCacheBootstrapper specifically, this alone is not enough since it explicitly sets the store's config connection to 'tenant'. That's why DatabaseCacheBootstrapper's $adjustCacheManagerUsing callback runs after and overrides those stores back to the original (central) connection.

Added datasets that use the database cache store + CacheTenancyBootstrapper to the relevant tests (globalCache and invalidation) to test regression (0cf7043), and the changes mentioned above (5e65c67) make these tests pass.

Summary by CodeRabbit

  • Bug Fixes

    • Database-backed cache stores now always use the configured central database connection, preventing caches from being tied to tenant connections and avoiding unintended cache behavior in multi-tenant setups.
  • Tests

    • Tests updated to reset cache-manager adjustments between runs and to reflect the corrected global cache behavior for database-backed caches.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 1, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a helper called during the globalCache binding to force database-backed cache stores to use the configured central DB connection; tests are updated to reset the provider callback and to use CacheTenancyBootstrapper for database cache-store cases.

Changes

Database Cache Connection Centralization

Layer / File(s) Summary
Central cache connection helper and integration
src/TenancyServiceProvider.php
Adds Illuminate\Cache\DatabaseStore import, calls makeDatabaseCacheStoresCentral($manager) inside the globalCache factory before applying static::$adjustCacheManagerUsing, and implements protected function makeDatabaseCacheStoresCentral(CacheManager $manager): void to rewire database store main and lock connections to the central DB connection.
Test updates and cleanup hooks
tests/CachedTenantResolverTest.php, tests/GlobalCacheTest.php
Reset TenancyServiceProvider::$adjustCacheManagerUsing to null in test setup/teardown and update database dataset cases to pair DatabaseTenancyBootstrapper with CacheTenancyBootstrapper instead of DatabaseCacheBootstrapper.

🎯 3 (Moderate) | ⏱️ ~20 minutes

🐰 A helper hops in, neat and central,
Rewiring stores so locks won't wander,
Tests tidy their hooks and pairings too,
Hops, nibbles, passes — cache stays true! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely summarizes the main change: enforcing the globalCache binding to use the central database connection when using database cache stores, which is the core objective of this PR.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-cache-invalidation

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 and usage tips.

@lukinovec lukinovec changed the title Add datasets to globalCache/invalidation tests as regression [4.x] Make globalCache always use the central connection Jun 1, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 1, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.94%. Comparing base (da7eb94) to head (20036ef).

Additional details and impacted files
@@             Coverage Diff              @@
##             master    #1462      +/-   ##
============================================
+ Coverage     85.90%   85.94%   +0.04%     
- Complexity     1170     1174       +4     
============================================
  Files           185      185              
  Lines          3412     3422      +10     
============================================
+ Hits           2931     2941      +10     
  Misses          481      481              

☔ 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.

@lukinovec
Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 1, 2026

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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 `@src/TenancyServiceProvider.php`:
- Around line 127-140: The loop eagerly instantiates every database cache store
by calling $manager->store($name)->getStore(), causing unnecessary connections;
instead, avoid materialization by registering a lazy decorator for each
configured database store using $manager->extend($name, ...), and inside that
extender wrap/return the real store and call setConnection(...) and
setLockConnection(...) on the DatabaseStore using $store['connection'] ??
$centralConnection and $store['lock_connection'] ?? $store['connection'] ??
$centralConnection so the central-connection fallback is applied only when a
store is actually resolved; reference $manager->extend, DatabaseStore,
setConnection, setLockConnection, $store and $centralConnection to locate and
implement the change.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: e78e02ab-9f44-436e-9714-85a7f2f2445b

📥 Commits

Reviewing files that changed from the base of the PR and between da7eb94 and 5e65c67.

📒 Files selected for processing (3)
  • src/TenancyServiceProvider.php
  • tests/CachedTenantResolverTest.php
  • tests/GlobalCacheTest.php

Comment thread src/TenancyServiceProvider.php
@lukinovec lukinovec marked this pull request as ready for review June 1, 2026 12:58
@lukinovec
Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 1, 2026

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@tests/CachedTenantResolverTest.php`:
- Line 168: The dataset leaves TenancyServiceProvider::$adjustCacheManagerUsing
mutated by the DatabaseTenancyBootstrapper case so the subsequent
CacheTenancyBootstrapper case inherits the callback; update the test fixture in
CachedTenantResolverTest (in the beforeEach/afterEach surrounding the dataset)
to explicitly reset TenancyServiceProvider::$adjustCacheManagerUsing to its
known default (e.g., null or the original default closure) in addition to the
existing Tenant::$extraCustomColumns reset so each case exercises
makeDatabaseCacheStoresCentral() independently.

In `@tests/GlobalCacheTest.php`:
- Line 168: Tests leave TenancyServiceProvider::$adjustCacheManagerUsing set by
DatabaseTenancyBootstrapper, causing stale static state that affects later
CacheTenancyBootstrapper assertions; reset the static between runs by explicitly
assigning the class default (e.g.
TenancyServiceProvider::$adjustCacheManagerUsing = null or the original default)
in the test suite setup/teardown (beforeEach()/afterEach()) in the
GlobalCacheTest so each test starts with a clean
TenancyServiceProvider::$adjustCacheManagerUsing state.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 574ac1d9-33d8-4426-852f-0208fe2e5108

📥 Commits

Reviewing files that changed from the base of the PR and between da7eb94 and fd1aa24.

📒 Files selected for processing (3)
  • src/TenancyServiceProvider.php
  • tests/CachedTenantResolverTest.php
  • tests/GlobalCacheTest.php

Comment thread tests/CachedTenantResolverTest.php
Comment thread tests/GlobalCacheTest.php
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 fixes globalCache behavior so that database-backed cache stores use the central (or explicitly configured) DB connection even when the app is currently in tenant context (notably when using DatabaseTenancyBootstrapper + CacheTenancyBootstrapper). This prevents global cache reads/writes and cache invalidation from accidentally targeting tenant databases.

Changes:

  • Adjust globalCache’s freshly-instantiated CacheManager to reset database cache stores onto the central/configured connection.
  • Add regression coverage for the database cache driver when used with CacheTenancyBootstrapper.
  • Reset TenancyServiceProvider::$adjustCacheManagerUsing in tests to avoid cross-test state leakage.

Reviewed changes

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

File Description
src/TenancyServiceProvider.php Ensures database cache stores on the globalCache manager are pointed at the central/configured DB connection.
tests/GlobalCacheTest.php Adds regression dataset for database cache + CacheTenancyBootstrapper and resets the static cache-manager adjuster between tests.
tests/CachedTenantResolverTest.php Adds regression dataset for database cache + CacheTenancyBootstrapper and resets the static cache-manager adjuster between tests.

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

@lukinovec lukinovec changed the title [4.x] Make globalCache always use the central connection [4.x] Make globalCache always use the central connection with database cache store Jun 5, 2026
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