# Laravel Health Laravel Health is a comprehensive health monitoring package for Laravel applications that allows developers to track the operational status of various application components through a flexible and extensible check system. The package provides out-of-the-box checks for common concerns like disk space, database connectivity, cache functionality, queue processing, and scheduler execution, while also supporting custom checks for application-specific requirements. The package operates by registering health checks that run on a scheduled basis (typically every minute via Laravel's scheduler), storing results in configurable storage backends, and sending notifications when issues are detected. Results can be accessed through web interfaces (both HTML and JSON), making it ideal for both human monitoring and automated health check systems like container orchestration platforms. The notification system supports multiple channels including email, Slack, and Oh Dear integration, with built-in throttling to prevent notification fatigue during extended outages. ## Registering Basic Health Checks Register health checks in a service provider to monitor your application's critical systems. ```php use Spatie\Health\Facades\Health; use Spatie\Health\Checks\Checks\UsedDiskSpaceCheck; use Spatie\Health\Checks\Checks\DatabaseCheck; use Spatie\Health\Checks\Checks\CacheCheck; // In App\Providers\AppServiceProvider or a custom HealthServiceProvider public function boot() { Health::checks([ UsedDiskSpaceCheck::new() ->warnWhenUsedSpaceIsAbovePercentage(70) ->failWhenUsedSpaceIsAbovePercentage(90), DatabaseCheck::new(), CacheCheck::new(), ]); } ``` ## Configuring Check Scheduling Control how frequently checks run using Laravel's scheduling syntax. ```php use Spatie\Health\Facades\Health; use Spatie\Health\Checks\Checks\UsedDiskSpaceCheck; use Spatie\Health\Checks\Checks\DatabaseCheck; Health::checks([ // Run every minute (default) DatabaseCheck::new(), // Run daily at 2 AM UsedDiskSpaceCheck::new() ->dailyAt('02:00') ->timezone('America/Los_Angeles'), // Run every 5 minutes CacheCheck::new()->cron('*/5 * * * *'), // Run hourly DatabaseCheck::new() ->name('hourly_db_check') ->hourly(), ]); ``` ## Running Health Checks via Command Line Execute health checks manually from the command line. ```bash # Run all registered health checks php artisan health:check # Run checks without storing results in the database php artisan health:check --do-not-store-results # Run checks without sending notifications php artisan health:check --no-notification # Make the command fail (exit code 1) if any check fails php artisan health:check --fail-command-on-failing-check # List all registered health checks php artisan health:list ``` ## Database Connection Health Check Monitor database connectivity with support for multiple connections. ```php use Spatie\Health\Checks\Checks\DatabaseCheck; Health::checks([ // Check default database connection DatabaseCheck::new(), // Check specific database connection DatabaseCheck::new() ->name('mysql_replica') ->connectionName('mysql_replica'), ]); ``` ## Cache System Health Check Verify cache functionality by writing and reading test values. ```php use Spatie\Health\Checks\Checks\CacheCheck; Health::checks([ // Check default cache driver CacheCheck::new(), // Check specific cache driver CacheCheck::new() ->name('redis_cache') ->driver('redis'), ]); ``` ## Redis Connection Health Check Monitor Redis connectivity for specific connection names. ```php use Spatie\Health\Checks\Checks\RedisCheck; use Spatie\Health\Checks\Checks\RedisMemoryUsageCheck; Health::checks([ // Check Redis connection RedisCheck::new() ->connectionName('default'), // Monitor Redis memory usage RedisMemoryUsageCheck::new() ->connectionName('default') ->failWhenAboveMb(1000), ]); ``` ## Queue System Health Check Monitor queue processing by tracking job execution timestamps. ```php use Spatie\Health\Checks\Checks\QueueCheck; Health::checks([ // Monitor default queue QueueCheck::new() ->failWhenHealthJobTakesLongerThanMinutes(5), // Monitor multiple queues QueueCheck::new() ->onQueue(['default', 'emails', 'notifications']) ->failWhenHealthJobTakesLongerThanMinutes(10), ]); // Schedule queue check jobs to run every minute // In app/Console/Kernel.php protected function schedule(Schedule $schedule) { $schedule->command('health:queue-check-heartbeat')->everyMinute(); } ``` ## Scheduler Health Check Verify that Laravel's task scheduler is running properly. ```php use Spatie\Health\Checks\Checks\ScheduleCheck; Health::checks([ ScheduleCheck::new() ->heartbeatMaxAgeInMinutes(2), ]); // In app/Console/Kernel.php, add the heartbeat command protected function schedule(Schedule $schedule) { $schedule->command('health:schedule-heartbeat')->everyMinute(); } ``` ## Debug Mode Health Check Ensure debug mode is set correctly for your environment. ```php use Spatie\Health\Checks\Checks\DebugModeCheck; Health::checks([ // Expect debug mode to be off in production DebugModeCheck::new() ->expectedToBe(false), // Expect debug mode to be on in local development DebugModeCheck::new() ->expectedToBe(true) ->if(app()->environment('local')), ]); ``` ## Environment Health Check Verify the application is running in the expected environment. ```php use Spatie\Health\Checks\Checks\EnvironmentCheck; Health::checks([ EnvironmentCheck::new() ->expectEnvironment('production'), ]); ``` ## URL Ping Health Check Monitor external service availability by pinging URLs. ```php use Spatie\Health\Checks\Checks\PingCheck; Health::checks([ // Basic ping check PingCheck::new() ->name('api_server') ->url('https://api.example.com/health') ->timeout(5) ->retryTimes(3), // POST request with headers PingCheck::new() ->name('webhook_endpoint') ->url('https://example.com/webhook') ->method('POST') ->headers([ 'Authorization' => 'Bearer ' . config('services.api.token'), 'Accept' => 'application/json', ]) ->failureMessage('Webhook endpoint is unreachable'), ]); ``` ## Conditional Health Checks Run checks conditionally based on environment or other criteria. ```php use Spatie\Health\Checks\Checks\DatabaseCheck; use Spatie\Health\Checks\Checks\RedisCheck; use Spatie\Health\Checks\Checks\HorizonCheck; Health::checks([ // Only run in production DatabaseCheck::new() ->if(app()->environment('production')), // Don't run in local environment RedisCheck::new() ->unless(app()->environment('local')), // Run only if Horizon is configured HorizonCheck::new() ->if(function () { return config('horizon.enabled') === true; }), ]); ``` ## Creating Custom Health Checks Create custom checks by extending the base Check class. ```php namespace App\Checks; use Spatie\Health\Checks\Check; use Spatie\Health\Checks\Result; class ApiResponseTimeCheck extends Check { protected string $url; protected int $maxResponseTimeMs = 2000; public function url(string $url): self { $this->url = $url; return $this; } public function maxResponseTime(int $milliseconds): self { $this->maxResponseTimeMs = $milliseconds; return $this; } public function run(): Result { $start = microtime(true); try { $response = \Illuminate\Support\Facades\Http::get($this->url); $responseTime = (microtime(true) - $start) * 1000; $result = Result::make() ->meta([ 'response_time_ms' => round($responseTime, 2), 'status_code' => $response->status(), ]) ->shortSummary(round($responseTime, 2) . 'ms'); if (!$response->successful()) { return $result->failed("API returned status {$response->status()}"); } if ($responseTime > $this->maxResponseTimeMs) { return $result->warning( "API response time ({$responseTime}ms) exceeded threshold ({$this->maxResponseTimeMs}ms)" ); } return $result->ok(); } catch (\Exception $e) { return Result::make() ->failed("Failed to reach API: {$e->getMessage()}"); } } } // Register the custom check Health::checks([ \App\Checks\ApiResponseTimeCheck::new() ->name('external_api') ->url('https://api.example.com/status') ->maxResponseTime(1500), ]); ``` ## HTTP Endpoints for Health Checks Expose health check results via HTTP routes for monitoring systems. ```php // routes/web.php // Simple health check (returns 200 or 503) Route::get('health', \Spatie\Health\Http\Controllers\SimpleHealthCheckController::class); // Detailed JSON health check (returns all check details) Route::get('health/json', \Spatie\Health\Http\Controllers\HealthCheckJsonResultsController::class); // Protected detailed health check with authentication Route::middleware('auth')->get( 'health/details', \Spatie\Health\Http\Controllers\HealthCheckJsonResultsController::class ); // HTML status page Route::get('health/status', \Spatie\Health\Http\Controllers\HealthCheckResultsController::class); // Force fresh results (runs checks immediately) // Add ?fresh=1 query parameter to any endpoint // Example: GET /health/json?fresh=1 ``` ## Configuring Notifications Configure notification channels for health check failures in config/health.php. ```php return [ 'notifications' => [ 'enabled' => true, 'notifications' => [ Spatie\Health\Notifications\CheckFailedNotification::class => ['mail', 'slack'], ], // Throttle notifications to prevent spam 'throttle_notifications_for_minutes' => 60, 'mail' => [ 'to' => 'ops@example.com', 'from' => [ 'address' => env('MAIL_FROM_ADDRESS', 'health@example.com'), 'name' => env('MAIL_FROM_NAME', 'Health Monitor'), ], ], 'slack' => [ 'webhook_url' => env('HEALTH_SLACK_WEBHOOK_URL'), 'channel' => '#alerts', 'username' => 'Health Monitor', ], ], ]; ``` ## Configuring Result Storage Configure where and how health check results are stored. ```php // config/health.php return [ 'result_stores' => [ // Store in database (default) Spatie\Health\ResultStores\EloquentHealthResultStore::class => [ 'connection' => env('DB_CONNECTION'), 'model' => Spatie\Health\Models\HealthCheckResultHistoryItem::class, 'keep_history_for_days' => 5, ], // Store in cache Spatie\Health\ResultStores\CacheHealthResultStore::class => [ 'store' => 'redis', ], // Store in JSON file Spatie\Health\ResultStores\JsonFileHealthResultStore::class => [ 'disk' => 's3', 'path' => 'health-checks/results.json', ], // Store in memory (useful for testing) Spatie\Health\ResultStores\InMemoryHealthResultStore::class, ], ]; ``` ## Oh Dear Integration Configure Oh Dear monitoring service integration for external health monitoring. ```php // config/health.php return [ 'oh_dear_endpoint' => [ 'enabled' => true, 'always_send_fresh_results' => true, 'secret' => env('OH_DEAR_HEALTH_CHECK_SECRET'), 'url' => '/oh-dear-health-check-results', ], ]; // The endpoint will be automatically registered when enabled // Access via: GET /oh-dear-health-check-results // Requires X-Secret-Token header matching OH_DEAR_HEALTH_CHECK_SECRET ``` ## Testing Health Checks Test health checks using the fake helper for predictable results. ```php use Spatie\Health\Facades\Health; use Spatie\Health\Checks\Checks\DatabaseCheck; use Spatie\Health\Checks\Result; use Spatie\Health\Enums\Status; // In a test public function test_health_endpoint_returns_failed_status() { Health::fake([ DatabaseCheck::class => Result::make() ->failed('Database connection failed'), ]); $response = $this->get('/health'); $response->assertStatus(503); } public function test_custom_check_detects_high_response_time() { $check = new \App\Checks\ApiResponseTimeCheck(); $result = $check ->url('https://slow-api.example.com') ->maxResponseTime(1000) ->run(); $this->assertTrue($result->status->isWarning()); $this->assertArrayHasKey('response_time_ms', $result->meta); } ``` ## Pausing and Resuming Health Checks Temporarily pause health checks during maintenance or deployments. ```bash # Pause all health checks php artisan health:pause # Resume health checks php artisan health:resume ``` ```php // Programmatically pause/resume use Spatie\Health\Commands\PauseHealthChecksCommand; use Illuminate\Support\Facades\Cache; // Pause Cache::put(PauseHealthChecksCommand::CACHE_KEY, true); // Resume Cache::forget(PauseHealthChecksCommand::CACHE_KEY); ``` ## Main Use Cases and Integration Patterns Laravel Health is designed for production applications that require reliable uptime monitoring and proactive issue detection. The primary use case is continuous monitoring of critical application components through scheduled health checks that run every minute, storing historical results in a database or cache for trend analysis and reporting. Teams typically integrate the package into their CI/CD pipelines using the `--fail-command-on-failing-check` flag to prevent deployments when health checks fail, and configure Slack or email notifications to alert on-call engineers immediately when issues arise. The throttling mechanism ensures that during extended outages, teams receive only one notification per hour rather than being overwhelmed with repeated alerts. For containerized applications and Kubernetes deployments, the SimpleHealthCheckController endpoint serves as a readiness/liveness probe that returns HTTP 200 for healthy applications and HTTP 503 for unhealthy ones, allowing orchestration platforms to automatically restart or redirect traffic from failing containers. Custom health checks enable application-specific monitoring such as third-party API availability, license validation, or business-critical background job processing. The package's Oh Dear integration extends monitoring beyond the application server itself—even if the entire server becomes unresponsive, Oh Dear can detect the absence of health check updates and trigger alerts through its independent monitoring infrastructure. The flexible result storage system allows teams to maintain historical data for capacity planning and incident post-mortems, with configurable retention periods to manage storage costs.