Skip to content

Commit

Permalink
Add pause and resume commands for health checks
Browse files Browse the repository at this point in the history
  • Loading branch information
faustoFF committed Jan 2, 2025
1 parent 7db119c commit b0507fa
Show file tree
Hide file tree
Showing 10 changed files with 188 additions and 2 deletions.
26 changes: 26 additions & 0 deletions src/Commands/PauseHealthChecksCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Spatie\Health\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;

class PauseHealthChecksCommand extends Command
{
public const CACHE_KEY = 'health_paused';
public const DEFAULT_TTL = 300;

protected $signature = 'health:pause {seconds=' . self::DEFAULT_TTL . '}';
protected $description = 'Pause all health checks for the giving time';

public function handle(): int
{
$seconds = (int) $this->argument('seconds');

Cache::put(self::CACHE_KEY, true, $seconds);

$this->comment('All health check paused until ' . now()->addSeconds($seconds)->toDateTimeString());

return self::SUCCESS;
}
}
21 changes: 21 additions & 0 deletions src/Commands/ResumeHealthChecksCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Spatie\Health\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;

class ResumeHealthChecksCommand extends Command
{
protected $signature = 'health:resume';
protected $description = 'Resume all health checks';

public function handle(): int
{
Cache::forget(PauseHealthChecksCommand::CACHE_KEY);

$this->comment('All health check resumed');

return self::SUCCESS;
}
}
7 changes: 7 additions & 0 deletions src/Commands/RunHealthChecksCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Exception;
use Illuminate\Console\Command;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Spatie\Health\Checks\Check;
use Spatie\Health\Checks\Result;
use Spatie\Health\Enums\Status;
Expand All @@ -25,6 +26,12 @@ class RunHealthChecksCommand extends Command

public function handle(): int
{
if (Cache::get(PauseHealthChecksCommand::CACHE_KEY)) {
$this->info('Checks paused');

return self::SUCCESS;
}

$this->info('Running checks...');

$results = $this->runChecks();
Expand Down
6 changes: 5 additions & 1 deletion src/HealthServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use Illuminate\Support\Facades\Route;
use Spatie\Health\Commands\DispatchQueueCheckJobsCommand;
use Spatie\Health\Commands\ListHealthChecksCommand;
use Spatie\Health\Commands\PauseHealthChecksCommand;
use Spatie\Health\Commands\ResumeHealthChecksCommand;
use Spatie\Health\Commands\RunHealthChecksCommand;
use Spatie\Health\Commands\ScheduleCheckHeartbeatCommand;
use Spatie\Health\Components\Logo;
Expand Down Expand Up @@ -33,7 +35,9 @@ public function configurePackage(Package $package): void
ListHealthChecksCommand::class,
RunHealthChecksCommand::class,
ScheduleCheckHeartbeatCommand::class,
DispatchQueueCheckJobsCommand::class
DispatchQueueCheckJobsCommand::class,
PauseHealthChecksCommand::class,
ResumeHealthChecksCommand::class,
);
}

Expand Down
7 changes: 6 additions & 1 deletion src/Http/Controllers/SimpleHealthCheckController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Cache;
use Spatie\Health\Commands\PauseHealthChecksCommand;
use Spatie\Health\Commands\RunHealthChecksCommand;
use Spatie\Health\ResultStores\ResultStore;
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
Expand All @@ -13,7 +15,10 @@ class SimpleHealthCheckController
{
public function __invoke(Request $request, ResultStore $resultStore): Response
{
if ($request->has('fresh') || config('health.oh_dear_endpoint.always_send_fresh_results')) {
if (
($request->has('fresh') || config('health.oh_dear_endpoint.always_send_fresh_results'))
&& Cache::missing(PauseHealthChecksCommand::CACHE_KEY)
) {
Artisan::call(RunHealthChecksCommand::class);
}

Expand Down
49 changes: 49 additions & 0 deletions tests/Commands/PauseChecksCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

use Illuminate\Contracts\Cache\Repository;
use Illuminate\Support\Facades\Cache;
use Spatie\Health\Commands\PauseHealthChecksCommand;

use function Pest\Laravel\artisan;

it('sets cache value to true for default ttl', function () {
$mockRepository = Mockery::mock(Repository::class);

$mockRepository->shouldReceive('put')
->once()
->with(
PauseHealthChecksCommand::CACHE_KEY,
true,
PauseHealthChecksCommand::DEFAULT_TTL
)
->andReturn(true);

Cache::swap($mockRepository);

Cache::shouldReceive('driver')->andReturn($mockRepository);

artisan(PauseHealthChecksCommand::class)
->assertSuccessful()
->expectsOutputToContain('All health check paused until');
});

it('sets cache value to true for custom ttl', function () {
$mockRepository = Mockery::mock(Repository::class);

$mockRepository->shouldReceive('put')
->once()
->with(
PauseHealthChecksCommand::CACHE_KEY,
true,
60
)
->andReturn(true);

Cache::swap($mockRepository);

Cache::shouldReceive('driver')->andReturn($mockRepository);

artisan(PauseHealthChecksCommand::class, ['seconds' => '60'])
->assertSuccessful()
->expectsOutputToContain('All health check paused until');
});
26 changes: 26 additions & 0 deletions tests/Commands/ResumeChecksCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

use Illuminate\Contracts\Cache\Repository;
use Illuminate\Support\Facades\Cache;
use Spatie\Health\Commands\PauseHealthChecksCommand;

use Spatie\Health\Commands\ResumeHealthChecksCommand;
use function Pest\Laravel\artisan;

it('forgets cache value', function () {
$mockRepository = Mockery::mock(Repository::class);

$mockRepository->shouldReceive('forget')
->once()
->with(PauseHealthChecksCommand::CACHE_KEY)
->andReturn(true);

Cache::swap($mockRepository);

Cache::shouldReceive('driver')->andReturn($mockRepository);

artisan(ResumeHealthChecksCommand::class)
->assertSuccessful()
->expectsOutput('All health check resumed')
;
});
21 changes: 21 additions & 0 deletions tests/Commands/RunChecksCommandTest.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?php

use Illuminate\Contracts\Cache\Repository;
use Illuminate\Support\Facades\Notification;
use Spatie\Health\Commands\PauseHealthChecksCommand;
use Spatie\Health\Commands\RunHealthChecksCommand;
use Spatie\Health\Enums\Status;
use Spatie\Health\Facades\Health;
Expand Down Expand Up @@ -125,3 +127,22 @@
artisan('health:check')->assertSuccessful();
artisan('health:check --fail-command-on-failing-check')->assertFailed();
});

it('does not perform checks if checks are paused', function () {
$mockRepository = Mockery::mock(Repository::class);

$mockRepository->shouldReceive('get')
->once()
->with(PauseHealthChecksCommand::CACHE_KEY)
->andReturn(true);

Cache::swap($mockRepository);

Cache::shouldReceive('driver')->andReturn($mockRepository);

artisan('health:check')->assertSuccessful()->expectsOutput('Checks paused');

$historyItems = HealthCheckResultHistoryItem::get();

expect($historyItems)->toHaveCount(0);
});
26 changes: 26 additions & 0 deletions tests/Http/Controllers/SimpleHealthCheckControllerTest.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

use Illuminate\Contracts\Cache\Repository;
use Spatie\Health\Commands\PauseHealthChecksCommand;
use Spatie\Health\Commands\RunHealthChecksCommand;
use Spatie\Health\Facades\Health;
use Spatie\Health\Http\Controllers\SimpleHealthCheckController;
Expand Down Expand Up @@ -44,3 +46,27 @@

assertMatchesSnapshot($json);
});

it('does not perform checks if checks are paused', function () {
artisan(RunHealthChecksCommand::class);

$mockRepository = Mockery::mock(Repository::class);

$mockRepository->shouldReceive('missing')
->once()
->with(PauseHealthChecksCommand::CACHE_KEY)
->andReturn(false);

Cache::swap($mockRepository);

Cache::shouldReceive('driver')->andReturn($mockRepository);

// If the RunHealthChecksCommand were called (instead of being skipped as expected),
// the test should fail with the error similar to:
// "Received Mockery_2_Illuminate_Contracts_Cache_Repository::get(), but no expectations were specified."
$json = getJson('/')
->assertOk()
->json();

assertMatchesSnapshot($json);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
healthy: true

0 comments on commit b0507fa

Please sign in to comment.