Skip to content

Commit 79952ac

Browse files
axlontaylorotwell
andauthored
[9.x] Add cache-based maintenance mode support (#40102)
* Add cache based maintenance mode support * Add a maintenance mode driver manager * Fix code style * formatting Co-authored-by: Taylor Otwell <[email protected]>
1 parent e7237f9 commit 79952ac

File tree

4 files changed

+210
-2
lines changed

4 files changed

+210
-2
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
3+
namespace Illuminate\Foundation;
4+
5+
use Illuminate\Contracts\Cache\Factory;
6+
use Illuminate\Contracts\Cache\Repository;
7+
use Illuminate\Contracts\Foundation\MaintenanceMode;
8+
9+
class CacheBasedMaintenanceMode implements MaintenanceMode
10+
{
11+
/**
12+
* The cache factory.
13+
*
14+
* @var \Illuminate\Contracts\Cache\Factory
15+
*/
16+
protected $cache;
17+
18+
/**
19+
* The cache store that should be utilized.
20+
*
21+
* @var string
22+
*/
23+
protected $store;
24+
25+
/**
26+
* The cache key to use when storing maintenance mode information.
27+
*
28+
* @var string
29+
*/
30+
protected $key;
31+
32+
/**
33+
* Create a new cache based maintenance mode implementation.
34+
*
35+
* @param \Illuminate\Contracts\Cache\Factory $cache
36+
* @param string $store
37+
* @param string $key
38+
* @return void
39+
*/
40+
public function __construct(Factory $cache, string $store, string $key)
41+
{
42+
$this->cache = $cache;
43+
$this->store = $store;
44+
$this->key = $key;
45+
}
46+
47+
/**
48+
* Take the application down for maintenance.
49+
*
50+
* @param array $payload
51+
* @return void
52+
*/
53+
public function activate(array $payload): void
54+
{
55+
$this->getStore()->put($this->key, $payload);
56+
}
57+
58+
/**
59+
* Take the application out of maintenance.
60+
*
61+
* @return void
62+
*/
63+
public function deactivate(): void
64+
{
65+
$this->getStore()->forget($this->key);
66+
}
67+
68+
/**
69+
* Determine if the application is currently down for maintenance.
70+
*
71+
* @return bool
72+
*/
73+
public function active(): bool
74+
{
75+
return $this->getStore()->has($this->key);
76+
}
77+
78+
/**
79+
* Get the data array which was provided when the application was placed into maintenance.
80+
*
81+
* @return array
82+
*/
83+
public function data(): array
84+
{
85+
return $this->getStore()->get($this->key);
86+
}
87+
88+
/**
89+
* Get the cache store to use.
90+
*
91+
* @return \Illuminate\Contracts\Cache\Repository
92+
*/
93+
protected function getStore(): Repository
94+
{
95+
return $this->cache->store($this->store);
96+
}
97+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace Illuminate\Foundation;
4+
5+
use Illuminate\Support\Manager;
6+
7+
class MaintenanceModeManager extends Manager
8+
{
9+
/**
10+
* Create an instance of the file based maintenance driver.
11+
*
12+
* @return \Illuminate\Foundation\FileBasedMaintenanceMode
13+
*/
14+
protected function createFileDriver(): FileBasedMaintenanceMode
15+
{
16+
return new FileBasedMaintenanceMode();
17+
}
18+
19+
/**
20+
* Create an instance of the cache based maintenance driver.
21+
*
22+
* @return \Illuminate\Foundation\CacheBasedMaintenanceMode
23+
*
24+
* @throws \Illuminate\Contracts\Container\BindingResolutionException
25+
*/
26+
protected function createCacheDriver(): CacheBasedMaintenanceMode
27+
{
28+
return new CacheBasedMaintenanceMode(
29+
$this->container->make('cache'),
30+
$this->config->get('app.maintenance.store') ?: $this->config->get('cache.default'),
31+
'illuminate:foundation:down'
32+
);
33+
}
34+
35+
/**
36+
* Get the default driver name.
37+
*
38+
* @return string
39+
*/
40+
public function getDefaultDriver(): string
41+
{
42+
return $this->config->get('app.maintenance.driver', 'file');
43+
}
44+
}

src/Illuminate/Foundation/Providers/FoundationServiceProvider.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace Illuminate\Foundation\Providers;
44

55
use Illuminate\Contracts\Foundation\MaintenanceMode as MaintenanceModeContract;
6-
use Illuminate\Foundation\FileBasedMaintenanceMode;
6+
use Illuminate\Foundation\MaintenanceModeManager;
77
use Illuminate\Http\Request;
88
use Illuminate\Log\Events\MessageLogged;
99
use Illuminate\Support\AggregateServiceProvider;
@@ -128,6 +128,11 @@ protected function registerExceptionTracking()
128128
*/
129129
public function registerMaintenanceModeManager()
130130
{
131-
$this->app->bind(MaintenanceModeContract::class, FileBasedMaintenanceMode::class);
131+
$this->app->singleton(MaintenanceModeManager::class);
132+
133+
$this->app->bind(
134+
MaintenanceModeContract::class,
135+
fn () => $this->app->make(MaintenanceModeManager::class)->driver()
136+
);
132137
}
133138
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
namespace Illuminate\Tests\Foundation;
4+
5+
use Illuminate\Contracts\Cache\Factory;
6+
use Illuminate\Contracts\Cache\Repository;
7+
use Illuminate\Foundation\CacheBasedMaintenanceMode;
8+
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
9+
use Mockery as m;
10+
use PHPUnit\Framework\TestCase;
11+
12+
class FoundationCacheBasedMaintenanceModeTest extends TestCase
13+
{
14+
use MockeryPHPUnitIntegration;
15+
16+
public function test_it_determines_whether_maintenance_mode_is_active()
17+
{
18+
$cache = m::mock(Factory::class, Repository::class);
19+
$cache->shouldReceive('store')->with('store-key')->andReturnSelf();
20+
21+
$manager = new CacheBasedMaintenanceMode($cache, 'store-key', 'key');
22+
23+
$cache->shouldReceive('has')->once()->with('key')->andReturnFalse();
24+
$this->assertFalse($manager->active());
25+
26+
$cache->shouldReceive('has')->once()->with('key')->andReturnTrue();
27+
$this->assertTrue($manager->active());
28+
}
29+
30+
public function test_it_retrieves_payload_from_cache()
31+
{
32+
$cache = m::mock(Factory::class, Repository::class);
33+
$cache->shouldReceive('store')->with('store-key')->andReturnSelf();
34+
35+
$manager = new CacheBasedMaintenanceMode($cache, 'store-key', 'key');
36+
37+
$cache->shouldReceive('get')->once()->with('key')->andReturn(['payload']);
38+
$this->assertSame(['payload'], $manager->data());
39+
}
40+
41+
public function test_it_stores_payload_in_cache()
42+
{
43+
$cache = m::spy(Factory::class, Repository::class);
44+
$cache->shouldReceive('store')->with('store-key')->andReturnSelf();
45+
46+
$manager = new CacheBasedMaintenanceMode($cache, 'store-key', 'key');
47+
$manager->activate(['payload']);
48+
49+
$cache->shouldHaveReceived('put')->once()->with('key', ['payload']);
50+
}
51+
52+
public function test_it_removes_payload_from_cache()
53+
{
54+
$cache = m::spy(Factory::class, Repository::class);
55+
$cache->shouldReceive('store')->with('store-key')->andReturnSelf();
56+
57+
$manager = new CacheBasedMaintenanceMode($cache, 'store-key', 'key');
58+
$manager->deactivate();
59+
60+
$cache->shouldHaveReceived('forget')->once()->with('key');
61+
}
62+
}

0 commit comments

Comments
 (0)