Search by

ervinsvilumsons / laravel-health

ervinsvilumsons

Laravel Health is a package that provides an easy way to check failed services in Laravel applications.

Package info

github.com/ervinsvilumsons/laravel-health

pkg:composer/ervinsvilumsons/laravel-health

Statistics

Installs: 6

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.3 2026-09-16 17:08 UTC

This package is auto-updated.

Last update: 2026-09-16 17:10:02 UTC


README

Latest Version on Packagist PHP 8.4+ Laravel 11+ Tests codecov License

Laravel Health provides a JSON health-check endpoint for Laravel applications. Built-in checks cover cache, database, mail, queue, and Redis connections. Checks run concurrently and each service reports up, skipped or down with its response time.

๐Ÿ“‹ Requirements

ReactPHP for asynchronous checks:

These dependencies are installed automatically via Composer.

๐Ÿ“ฆ Installation

composer require ervinsvilumsons/laravel-health

Publish the package configuration when you need to customize it:

php artisan vendor:publish --tag=health-manager

๐Ÿงฉ Built-in Services

The package includes these service classes:

Service Configuration connection Default
Cache CACHE_STORE Enabled
Database DB_CONNECTION Enabled
Mail MAIL_MAILER Disabled
Queue QUEUE_CONNECTION Disabled
Redis REDIS_CLIENT Disabled

Enable a built-in service in config/health-manager.php:

'queue' => [
    'enabled' => true,
    'connection' => env('QUEUE_CONNECTION', 'database'),
    'class' => QueueService::class,
],

๐Ÿš€ Quick Start

The package registers its service provider through Laravel package discovery. The health endpoint is available at:

GET /api/health

The default response uses JSON:API-style data.attributes fields:

{
  "data": {
    "id": null,
    "type": "health-check",
    "attributes": {
      "timestamp": "2026-09-09T12:00:00.000000Z",
      "services": [
        {
          "name": "Database",
          "connection": "sqlite",
          "status": "up",
          "message": null,
          "responseTime": 4.12
        }
      ]
    }
  }
}

Configuration

return [
    'route' => [
        'path' => env('HEALTH_PATH', '/health'),
        'name' => 'health.check',
    ],

    'throttle' => [
        'max_attempts' => 30,
        'decay_seconds' => 60,
        'path' => storage_path('framework/cache/health-rate-limit'),
    ],

    'event' => [
        'title' => 'Service Alert',
        'message' => 'Following services are down:',
        'level' => 'error',
    ],

    'response' => [
        'service_timeout' => 1,
        'include_details' => env('HEALTH_DEBUG', false),
    ],

    'schedule' => [
        'prune_rate_limits' => true,
    ],

    'services' => [
        'database' => [
            'enabled' => true,
            'connection' => env('DB_CONNECTION', 'sqlite'),
            'class' => DatabaseService::class,
        ],
    ],
];

Custom Health Services

Create a class that extends HealthService. The class must provide a display name, connection label, and asynchronous checkAsync() method.

<?php

namespace App\Health;

use ErvinsVilumsons\LaravelHealth\Services\HealthService;
use Illuminate\Support\Facades\Config;
use React\Promise\PromiseInterface;
use React\Socket\Connector;

class BillingService extends HealthService
{
    private readonly string $host;

    private readonly int $port;

    public function __construct()
    {
        $this->host = Config::string('billing.host');
        $this->port = (int) Config::string('billing.port');
    }

    public function name(): string
    {
        return 'Billing';
    }

    public function connection(): mixed
    {
        return Config::string('health-manager.services.billing.connection');
    }

    protected function checkAsync(): PromiseInterface
    {
        $connector = new Connector(['timeout' => $this->getTimeout()]);

        return $connector
            ->connect("{$this->host}:{$this->port}")
            ->then(function ($connection): void {
                $connection->close();
            });
    }
}

Register it in config/health-manager.php:

'billing' => [
    'enabled' => true,
    'connection' => 'billing.internal:443',
    'class' => \App\Health\BillingService::class,
],

Failure Handling

A failed checkAsync() promise does not make the whole report fail. If one of services is marked down, a ServiceFailed event is dispatched. Response messages are only included when health-manager.response.include_details is enabled.

Then customize app/Listeners/HandleFailedService.php to send alerts, log metadata, or notify an incident system:

<?php

namespace App\Listeners;

use ErvinsVilumsons\LaravelHealth\Events\ServiceFailed;
use Illuminate\Support\Facades\Log;

class HandleFailedService
{
    public function handle(ServiceFailed $event): void
    {
        dispatch(function () use ($event) {
            Log::error('Health check failed', [
                'title' => $event->title,
                'message' => $event->message,
                'context' => $event->context,
                'level' => $event->level,
            ]);
        })->afterResponse();
    }
}

๐Ÿ›ก๏ธ Rate Limiting

The health endpoint is rate limited per client IP by default. Limits are configured under health-manager.throttle:

'throttle' => [
    'max_attempts' => 30,
    'decay_seconds' => 60,
    'path' => storage_path('framework/cache/health-rate-limit'),
],
Option Description
max_attempts Maximum number of requests allowed within the decay window.
decay_seconds Length of the rate-limit window, in seconds.

State is stored as JSON files under storage/framework/cache/health-rate-limit/ โ€” one file per hashed key. No cache or database table is required, so the limiter works even when the cache backend itself is unhealthy.

When a client exceeds the limit, the endpoint returns 429 Too Many Requests with a Retry-After header indicating how many seconds remain until the window resets.

Set max_attempts to 0 to disable throttling entirely (every request is allowed).

๐Ÿงน Console Commands

health:prune-rate-limits

Removes rate-limiter state files whose decay window has already expired. Invalid, empty, or malformed state files are also removed.

php artisan health:prune-rate-limits

The command is registered automatically and scheduled hourly by the package's service provider. You do not need to wire anything into app/Console/Kernel.php or routes/console.php.

Sample output:

Pruned 4 expired rate limiter file(s), kept 12.

If you prefer to control the schedule yourself, disable it in config/health-manager.php:

'schedule' => [
    'prune_rate_limits' => false,
],

โš–๏ธ License

Laravel Health Manager is released under the MIT License.