This bundle can be used to easily write health checks and expose endpoints which can be used by e.g. Kubernetes to determine the health of the application.
This bundle consists of two core components that interweave with eachother, checkers and checks.
- A (health) check is an component which contains logic to check if the system is behaving correctly.
- A (health) checker runs these checks when needed. For example when the endpoint
/healthz
is requested.
This package can be installed using composer:
composer require browncat/healthcheck-bundle
This bundle comes with a set of endpoints which can be enabled to expose the following set of endpoints:
/health/liveness
Returns 503 if one or multiple checks fail. Coupled toLivenessChecker
/health/readiness
Returns 503 if one or multiple checks fail. Coupled toReadinessChecker
/health/startup
Returns 503 if one or multiple checks fail. Coupled toStartupChecker
/healthz
JSON result of all checks, returns 503 if one or multiple checks fail.
To enable them all add the following to your routes.yaml
:
health:
resource: "@HealthCheckBundle/Resources/config/routes.xml"
This bundle comes with some pre defined health checks. These checks are not enabled by default as to not get into the way of your workflow. They can be enabled and configured through Symfony's config component.
To enable for example the check doctrine.connection
create or modify the file config/packages/healthcheck.yaml
and add the following:
# config/packages/healthcheck.yaml
health_check:
checks:
doctrine.connection:
A list of package provided health checks can be found here.
The config above will enable the doctrine connection check for all available checkers. To use a subset of checkers add the following to the config:
# config/packages/healthcheck.yaml
health_check:
checks:
doctrine.connection:
checkers:
- Browncat\HealthCheckBundle\Checker\LivenessChecker
- Browncat\HealthCheckBundle\Checker\ReadinessChecker
A list of availble checkers can be found here
id | description | since |
---|---|---|
doctrine.connection | Checks if all connections configured in doctrine work. | v0.1.0 |
Health checks are defined in classes extending Browncat\HealthCheckBundle\Check\HealthCheck
. For example, you may want to check the connection between the application and a remote system:
// src/Check/ExampleCheck.php
<?php
namespace App\Check;
use Browncat\HealthCheckBundle\Check\HealthCheck;
use Browncat\HealthCheckBundle\Checker\LivenessChecker;
use Browncat\HealthCheckBundle\Checker\ReadinessChecker;
use Psr\Container\ContainerInterface;
final class ExampleCheck extends HealthCheck
{
// Name of the health check
protected $name = 'example:connection';
// List of checkers who should execute this check.
public static $checkers = [ReadinessChecker::class, LivenessChecker::class];
public function __construct(ContainerInterface $container)
{
if ($container->has('example')) {
$exampleService = $container->get('example');
if (!$exampleService->isConnected()) {
$this->succeeded = false;
$this->reasonPhrase = "Could not establish connection to example " . $connection->getName() . ".";
} else {
$this->succeeded = true;
}
} else {
$this->skipped = true;
$this->reasonPhrase = "example is not installed so this check is skipped.";
}
}
}
Health checks must be registered as services and tagged with the health_check.check
tag. If you’re using the default services.yaml configuration, this is already done for you, thanks to autoconfiguration.
A check should have a common name. This makes sure it can be located if a big list of checks is executed. A check can be named by populating the proteced $name
.
// src/Check/ExampleCheck.php
use Browncat\HealthCheckBundle\Check\HealthCheck;
final class ExampleCheck extends HealthCheck
{
protected $name = 'example:connection';
...
}
A check can be failed or passed by passing a boolean value to the $succeeded
propety.
// src/Check/ExampleCheck.php
...
use Browncat\HealthCheckBundle\Check\HealthCheck;
...
final class ExampleCheck extends HealthCheck
{
public function __construct(SomeService $someService)
{
if ($someService->isLoaded() {
$this->succeeded = true
} else {
$this->succeeded = false;
// (optional) set a reason for the failed test
$this->reasonPhrase = "SomeService Could not be loaded!";
}
}
}
To skip a check set the property $skipped
to true.
// src/Check/ExampleCheck.php
...
use Browncat\HealthCheckBundle\Check\HealthCheck;
use Psr\Container\ContainerInterface;
...
final class ExampleCheck extends HealthCheck
{
public function __construct(ContainerInterface $container)
{
if (!$container->has('someService')) {
$this->skipped = true;
$this->reasonPhrase = 'SomeService is skipped because it does not exist.';
}
...
}
}
By default all checkers (readiness, liveness and maybe some other configured ones) run the check you've written. If you want to narrow the check down to only run with a specific checker populate public static $checkers
with the class references of the desired checker.
// src/Check/ExampleCheck.php
use Browncat\HealthCheckBundle\Check\HealthCheck;
use Browncat\HealthCheckBundle\Checker\ReadinessChecker;
final class ExampleCheck extends HealthCheck
{
public static $checkers = [ReadinessChecker::class];
...
}
Browncat\HealthCheckBundle\Checker\LivenessChecker
Browncat\HealthCheckBundle\Checker\ReadinessChecker
Browncat\HealthCheckBundle\Checker\StartupChecker
Browncat\HealthCheckBundle\Checker\GlobalHealthChecker
(this one processes all registered checks no matter what)