ans-group / laravel-health-check Goto Github PK
View Code? Open in Web Editor NEWA package for checking the health of your Laravel & Lumen applications
Home Page: https://ukfast.co.uk/open-source.html
License: MIT License
A package for checking the health of your Laravel & Lumen applications
Home Page: https://ukfast.co.uk/open-source.html
License: MIT License
We need to add GitHub Actions for the CI process.
We will use a config similar to the one created as an experiment in our PHP SDK repo.
This will allows us to ensure any changes made to the package will work on all of our supported PHP versions/dependencies. We can also expand our workflows to greet new contributors etc.
None.
A php artisan healthcheck:status
command which will output the status of all your services, exiting with a status code of 1 if it fails
I think one advantage of this package is that it makes setting your project up easier, as you can hit the endpoint and see what services you still need to configure. However, instead of getting users to hit an endpoint and read a load of JSON, it'd be more convenient to do it straight from the CLI
Currently it is possible to configure custom healthchecks what is pretty nice! In addition it would be nice if a check can
also add custom http header to the response in order to react on them by reading that header from the response
You could easly add more information to the response
PackageSecurityHealthCheck uses sensiolabs/security-checker
which has been abandoned since January and the underlying API no longer functions.
If we want to keep the check working, I can open a PR to have it use enlightn/security-checker
instead. However, based on the fact that it was broken for nearly a year without anyone noticing, I'm not sure there's demand for it.
v1.x
branchPackageSecurityHealthCheck
(#63)FtpHealthCheck
to use flysystem v3Add a new status to https://github.com/ukfast/laravel-health-check/blob/master/src/Status.php for Degraded
health checks, along with associated helper methods to report and check for this new status. This would be used for checks that are necessary for full functionality of the application in question but do not result in complete failure of the application.
This will give services an official way to report health of dependencies that do not fully result in service failure without reporting an unhealthy state.
Say there is a service whose controller simply accepts a request and creates a Job to be run later. If the queue is up, but a third-party service the worker needs to process that job is down, the running application is able to continue as it can continue creating Jobs. It would be beneficial to report the worker process unhealthy status without reporting the application as fully unhealthy.
The name Degraded
seems to be common among other services.
https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/upstream/load_balancing/degraded
https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/health-enhanced-status.html
We should add a QueueHealthCheck
to the package.
This will be used broadly across various apps, so is worth including in the core package.
This check would need to be able to run for multiple drivers, and should clean up after itself - we don't want to leave anything sat in queues after the check completes.
In https://github.com/ukfast/laravel-health-check/pull/53/files, new config values were added without a fallback.
This was a breaking change for those who have a custom config file, as the new config now returns null, so the paths change from /health and /ping to both be /.
/ping
and /health
200 responses to /ping
and /health
instead of 404s
Add a fallback to the config values
N/a
Out of the box, this package errors on Lumen 7.1.0 as it attempts to check for a database connection in the array named "default", rather than using the default connection.
composer create-project --prefer-dist laravel/lumen
composer require ukfast/laravel-health-check
$app->register(\\UKFast\\HealthCheck\\HealthCheckServiceProvider::class);
to bootstrap/app.php
artisan vendor:publish --provider="UKFast\HealthCheck\HealthCheckServiceProvider"
to create config/healthcheck.php
http://<IP>/health
and get the following error:{"status":"PROBLEM","log":{"status":"OK"},"database":{"status":"PROBLEM","message":"Could not connect to db","context":{"connection":"default","exception":{"error":"Database connection [default] not configured.","class":"InvalidArgumentException","line":152,"file":"\/var\/www\/vendor\/illuminate\/database\/DatabaseManager.php","trace":["#0 \/var\/www\/vendor\/illuminate\/database\/DatabaseManager.php(115): Illuminate\\Database\\DatabaseManager->configuration()","#1 \/var\/www\/vendor\/illuminate\/database\/DatabaseManager.php(86): Illuminate\\Database\\DatabaseManager->makeConnection()","#2 \/var\/www\/vendor\/ukfast\/laravel-health-check\/src\/Checks\/DatabaseHealthCheck.php(25): Illuminate\\Database\\DatabaseManager->connection()","#3 \/var\/www\/vendor\/ukfast\/laravel-health-check\/src\/Controllers\/HealthCheckController.php(19): UKFast\\HealthCheck\\Checks\\DatabaseHealthCheck->status()","#4 [internal function]: UKFast\\HealthCheck\\Controllers\\HealthCheckController->UKFast\\HealthCheck\\Controllers\\{closure}()","#5 \/var\/www\/vendor\/illuminate\/support\/Collection.php(638): array_map()","#6 \/var\/www\/vendor\/ukfast\/laravel-health-check\/src\/Controllers\/HealthCheckController.php(20): Illuminate\\Support\\Collection->map()","#7 [internal function]: UKFast\\HealthCheck\\Controllers\\HealthCheckController->__invoke()","#8 \/var\/www\/vendor\/illuminate\/container\/BoundMethod.php(33): call_user_func_array()","#9 \/var\/www\/vendor\/illuminate\/container\/Util.php(36): Illuminate\\Container\\BoundMethod::Illuminate\\Container\\{closure}()","#10 \/var\/www\/vendor\/illuminate\/container\/BoundMethod.php(91): Illuminate\\Container\\Util::unwrapIfClosure()","#11 \/var\/www\/vendor\/illuminate\/container\/BoundMethod.php(35): Illuminate\\Container\\BoundMethod::callBoundMethod()","#12 \/var\/www\/vendor\/illuminate\/container\/Container.php(592): Illuminate\\Container\\BoundMethod::call()","#13 \/var\/www\/vendor\/laravel\/lumen-framework\/src\/Concerns\/RoutesRequests.php(376): Illuminate\\Container\\Container->call()","#14 \/var\/www\/vendor\/laravel\/lumen-framework\/src\/Concerns\/RoutesRequests.php(319): Laravel\\Lumen\\Application->callControllerCallable()","#15 \/var\/www\/vendor\/laravel\/lumen-framework\/src\/Concerns\/RoutesRequests.php(278): Laravel\\Lumen\\Application->callControllerAction()","#16 \/var\/www\/vendor\/laravel\/lumen-framework\/src\/Concerns\/RoutesRequests.php(258): Laravel\\Lumen\\Application->callActionOnArrayBasedRoute()","#17 \/var\/www\/vendor\/laravel\/lumen-framework\/src\/Concerns\/RoutesRequests.php(416): Laravel\\Lumen\\Application->Laravel\\Lumen\\Concerns\\{closure}()","#18 \/var\/www\/vendor\/laravel\/lumen-framework\/src\/Concerns\/RoutesRequests.php(259): Laravel\\Lumen\\Application->sendThroughPipeline()","#19 \/var\/www\/vendor\/laravel\/lumen-framework\/src\/Concerns\/RoutesRequests.php(165): Laravel\\Lumen\\Application->handleFoundRoute()","#20 \/var\/www\/vendor\/laravel\/lumen-framework\/src\/Concerns\/RoutesRequests.php(416): Laravel\\Lumen\\Application->Laravel\\Lumen\\Concerns\\{closure}()","#21 \/var\/www\/vendor\/laravel\/lumen-framework\/src\/Concerns\/RoutesRequests.php(171): Laravel\\Lumen\\Application->sendThroughPipeline()","#22 \/var\/www\/vendor\/laravel\/lumen-framework\/src\/Concerns\/RoutesRequests.php(108): Laravel\\Lumen\\Application->dispatch()","#23 \/var\/www\/public\/index.php(28): Laravel\\Lumen\\Application->run()","#24 {main}"]}}},"env":{"status":"OK"}}
Code should work out of the box on default install (providing DB_ .env variables are correctly set):
{"status":"OK","log":{"status":"OK"},"database":{"status":"OK"},"env":{"status":"OK"}}
Use empty string in $connection
when using default database. Pull request attached in #8
The complete exception should not be returned as this may tell malicious parties some information about your app or infrastructure you may not like to tell everyone.
A simple solution would be defining a closure within the config to configure who is allowed to see the message and context of the problem.
I found that CacheSchedulerRunning.php & CacheHealthCheck.php both use "cache::put(...)"
The $ttl parameter is not rigorous enough. Before laravel 5.8, $ttl was in minutes.
see: https://laravel-news.com/cache-ttl-change-coming-to-laravel-5-8
We should add an SmtpAuthHealthCheck
to the package.
This will be used broadly across various apps, so is worth including in the core package.
We could surface a HealthCheck
facade which would allow this package to be useful outside of the /health
endpoint.
People can add handling based on whether a certain check passes.
Prevents potential issues with unreliable external services.
I think the following would be a good way to interact with the facade.
if (HealthCheck::passes('env')) {
continue;
}
/health
endpoint using middleware. There's no way to retrieve the user making the request ($request->user()
returns null
). Am I missing something?role:admin
)?Use existing middleware, e.g.:
'middleware' => [
\App\Http\Middleware\Authenticate::class,
],
or try with a custom one (try to dump the user) and visit the /health
endpoint.
As you can see I was redirected to the login page, but since I was already logged in, the app redirected me back to the home page.
If the user is authenticated, the user object should be accessible so I could make some additional authorization checks.
Works fine when the middleware
parameter is empty or contains a middleware which does not try to access the user object.
Tested with Laravel 8.76.1.
With the following code, you can easily check if Laravel Horizon is active. Just create a custom Healthcheck.
<?php
namespace App\HealthChecks;
use Laravel\Horizon\Contracts\MasterSupervisorRepository;
use UKFast\HealthCheck\HealthCheck;
use UKFast\HealthCheck\Status;
class HorizonHealthCheck extends HealthCheck
{
protected $name = 'horizon';
private MasterSupervisorRepository $masterSupervisorRepository;
/**
* @param MasterSupervisorRepository $masterSupervisorRepository
*/
public function __construct(MasterSupervisorRepository $masterSupervisorRepository)
{
$this->masterSupervisorRepository = $masterSupervisorRepository;
}
/**
* @return Status
*/
public function status(): Status
{
if (! $masters = $this->masterSupervisorRepository->all()) {
return $this->problem('Horizon is inactive.');
}
return collect($masters)->contains(function ($master) {
return $master->status === 'paused';
}) ? $this->problem('Horizon is paused.') : $this->okay();
}
}
We should add a CacheHealthCheck
to the package.
It's a useful part of the core Laravel framework, widely used in different apps.
Cache check should support multiple cache stores and not be reliant on a particular implementation.
A health check for memcached would be nice to have
Memcached status can be checkd with that health check
Add support for Illuminate 8.x
Allows people to use health check on the latest version of the framework.
None.
It would be nice to have an optional healthcheck that checks if all pending migrations have been applied.
Applications can go live/be indicated as healthy when all migrations have been applied
When using a redis cluster the RedisHealthCheck fails. This is due to the fact that a RedisCluster connection requires an argument (which it uses to determine which host in the cluster to ping). An ErrorException is thrown with the following message: RedisCluster::ping() expects at least 1 parameter, 0 given
.
Steps to reproduce the behavior:
RedisCluster::ping() expects at least 1 parameter, 0 given
(screenshot below)// config/database.php
'redis' => [
'client' => 'phpredis',
'clusters' => [
'options' => [
'cluster' => 'redis',
'password' => env('REDIS_PASSWORD', null),
'parameters' => [
'scheme' => env('REDIS_SCHEME', 'tcp'),
]
],
'default' => [
[
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => '0',
],
],
],
],
config/healthcheck.php
'checks' => [
UKFast\HealthCheck\Checks\RedisHealthCheck::class,
],
The healthcheck should check whether we're using a cluster connection, and ping each master node.
I've implemented a custom check in our system to get around this, which checks whether the redis connection (from the facade) is a cluster connection, and if so pings each master node in turn. It may need to account for other scenarios, but I think this will work with most laravel/Lumen installations out of the box.
A couple of considerations to make this more widely applicable:
<?php
use Exception;
use UKFast\HealthCheck\HealthCheck;
use Illuminate\Support\Facades\Redis;
use Illuminate\Redis\Connections\PhpRedisClusterConnection;
class RedisHealthCheck extends HealthCheck
{
protected $name = 'redis';
public function status()
{
try {
if ($this->isUsingPhpRedis()) {
$this->handlePhpRedisPing();
} else {
// Think this is all we can do for predis?
Redis::ping();
}
} catch (Exception $e) {
return $this->problem('Failed to connect to redis', [
'exception' => $this->exceptionContext($e),
]);
}
return $this->okay();
}
protected function isUsingPhpRedis()
{
return config('database.redis.client') == 'phpredis';
}
protected function handlePhpRedisPing()
{
$redis = Redis::connection();
if ($redis instanceof PhpRedisClusterConnection) {
foreach ($redis->_masters() as $master) {
Redis::ping($master);
}
return;
}
$redis->ping();
}
}
I can create a pull request for this, but wanted to make sure I went through an issue first :)
~
A php artisan make:check MyHealthCheck
command which generates the health check stub under App\Checks
.
This will make it easier to use the package. It would also be a faster method of generating custom checks.
We should add a StorageHealthCheck
to the package.
It's a useful part of the core Laravel framework, widely used in different apps.
The storage check should support multiple drivers, similar to the CacheHealthCheck
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.