-
Notifications
You must be signed in to change notification settings - Fork 11.8k
Description
Laravel Version
12.51.0
PHP Version
8.4.17
Database Driver & Version
No response
Description
This change #57584 introduces a breaking issue for our test suite.
After upgrading to v12.51.0, hundreds of our tests started failing. Our application is multi-tenant and uses a database per tenant architecture. In our CI setup, we intentionally share a single test tenant across all parallel test processes. This avoids creating dozens of tenant databases (for example, 32 databases on a 32-core machine), which would significantly increase setup time and resource usage.
With the new cache prefix / isolation behavior per parallel process, this setup no longer works. The shared tenant relies on a consistent cache namespace across processes, but the automatic isolation now prevents that, causing test failures.
Is there a recommended way to opt out of cache isolation for parallel testing, or to configure a shared cache namespace across processes?
Steps To Reproduce
- Create a fresh Laravel 12 application with Redis:
laravel new cache-isolation-bug
cd cache-isolation-bug
composer require predis/predis- Configure Redis as the cache driver in
.env:
CACHE_STORE=redis
CACHE_PREFIX=tenant_shared
- Seed shared tenant details in the base
TestCase, simulating tenant config that is cached once during CI bootstrap and read by all processes:
// tests/TestCase.php
namespace Tests;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Support\Facades\Redis;
abstract class TestCase extends BaseTestCase
{
protected function setUp(): void
{
parent::setUp();
// Simulate shared tenant details seeded during CI bootstrap.
// Written directly to Redis with the expected prefix to bypass
// any prefix manipulation by the framework.
$tenantDetails = [
'id' => 'tenant-001',
'name' => 'Acme Travel Agency',
'domain' => 'acme.example.com',
'database' => 'tenant_acme',
'timezone' => 'Europe/Zurich',
'locale' => 'de_CH',
];
Redis::set('tenant_shared_tenant:details', serialize($tenantDetails));
}
}- Create two test files so they run in separate parallel processes:
// tests/Feature/TenantDetailsAlphaTest.php
namespace Tests\Feature;
use Illuminate\Support\Facades\Cache;
use Tests\TestCase;
class TenantDetailsAlphaTest extends TestCase
{
public function test_process_can_read_shared_tenant_details(): void
{
$tenant = Cache::get('tenant:details');
$this->assertNotNull($tenant, sprintf(
'Shared tenant details not found in cache. '
. 'Cache prefix is "%s" — expected "tenant_shared_". '
. 'Per-process isolation has changed the prefix.',
Cache::getPrefix()
));
$this->assertEquals('tenant-001', $tenant['id']);
$this->assertEquals('Acme Travel Agency', $tenant['name']);
$this->assertEquals('tenant_acme', $tenant['database']);
}
}// tests/Feature/TenantDetailsBravoTest.php
namespace Tests\Feature;
use Illuminate\Support\Facades\Cache;
use Tests\TestCase;
class TenantDetailsBravoTest extends TestCase
{
public function test_process_can_read_shared_tenant_details(): void
{
$tenant = Cache::get('tenant:details');
$this->assertNotNull($tenant, sprintf(
'Shared tenant details not found in cache. '
. 'Cache prefix is "%s" — expected "tenant_shared_". '
. 'Per-process isolation has changed the prefix.',
Cache::getPrefix()
));
$this->assertEquals('acme.example.com', $tenant['domain']);
$this->assertEquals('Europe/Zurich', $tenant['timezone']);
$this->assertEquals('de_CH', $tenant['locale']);
}
}- Run tests in parallel:
php artisan test --parallel --processes=2