Giter Site home page Giter Site logo

ans-group / laravel-health-check Goto Github PK

View Code? Open in Web Editor NEW
152.0 11.0 41.0 200 KB

A package for checking the health of your Laravel & Lumen applications

Home Page: https://ukfast.co.uk/open-source.html

License: MIT License

PHP 100.00%
laravel-health-check laravel lumen health-checks hacktoberfest

laravel-health-check's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

laravel-health-check's Issues

Fix Backwards Incompatible Config Additions

What is the issue?

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 /.

Steps To Reproduce

  • Update a laravel/lumen application with an existing custom config file to the latest version
  • Hit /ping and /health
  • Both get 404 responses

Expected behaviour

200 responses to /ping and /health instead of 404s

Possible fixes

Add a fallback to the config values

Additional context

N/a

Add QueueHealthCheck

What is the feature?

We should add a QueueHealthCheck to the package.

What benefits will this change bring?

This will be used broadly across various apps, so is worth including in the core package.

Additional context

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.

Add health check if migrations are uptodate

What is the feature?

It would be nice to have an optional healthcheck that checks if all pending migrations have been applied.

What benefits will this change bring?

Applications can go live/be indicated as healthy when all migrations have been applied

Add health check for memcached

What is the feature?

A health check for memcached would be nice to have

What benefits will this change bring?

Memcached status can be checkd with that health check

The package behind PackageSecurityHealthCheck is abandoned

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.

Surface a healthcheck status command

What is the feature?

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

What benefits will this change bring?

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

Add possibility to add custom headers from checks

What is the feature?

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

What benefits will this change bring?

You could easly add more information to the response

Surface a make:check command

What is the feature?

A php artisan make:check MyHealthCheck command which generates the health check stub under App\Checks.

What benefits will this change bring?

This will make it easier to use the package. It would also be a faster method of generating custom checks.

Lumen 7.1.0 - Database connection [default] not configured

What is the issue?

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.

Steps To Reproduce

  1. Install Lumen 7.1.0 (current) using composer create-project --prefer-dist laravel/lumen
  2. Install laravel-health-check using composer require ukfast/laravel-health-check
  3. Add $app->register(\\UKFast\\HealthCheck\\HealthCheckServiceProvider::class); to bootstrap/app.php
  4. Run artisan vendor:publish --provider="UKFast\HealthCheck\HealthCheckServiceProvider" to create config/healthcheck.php
  5. Open 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"}}

Expected behaviour

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"}}

Possible fixes

Use empty string in $connection when using default database. Pull request attached in #8

Add Degraded health check status

What is the feature?

Add 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.

What benefits will this change bring?

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.

Additional context

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

https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.diagnostics.healthchecks.healthstatus?view=dotnet-plat-ext-5.0

Do not report exception information

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.

Add support for Laravel/Lumen 8.x

What is the feature?

Add support for Illuminate 8.x

What benefits will this change bring?

Allows people to use health check on the latest version of the framework.

Additional context

None.

Add SmtpAuthHealthCheck

What is the feature?

We should add an SmtpAuthHealthCheck to the package.

What benefits will this change bring?

This will be used broadly across various apps, so is worth including in the core package.

Additional context

  • The check should try and connect to the configured SMTP server and expect to receive an SMTP EHLO response.
  • It should also then attempt to perform auth against the server, using configured credentials e.g. https://www.ndchost.com/wiki/mail/test-smtp-auth-telnet
  • If either of these do not complete successfully, the check should fail.
  • A relevant and detailed error message should be presented back in the JSON data.

Horizon Healthcheck

What is the feature?

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();
    }
}

Support for clusters in RedisHealthCheck

What is the issue?

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

Steps to reproduce the behavior:

  1. You'll need a redis cluster, using redis' built-in clustering mechanism, rather than replicated nodes (i.e. sentinel)
  2. Configure a laravel app to connect to this cluster (snippet 1 below)
  3. Add the RedisHealthCheck to the healthcheck configuration (snippet 2 below)
  4. Hit the healthcheck endpoint
  5. The redis check should report a problem with the following ErrorException: RedisCluster::ping() expects at least 1 parameter, 0 given (screenshot below)

Snippet 1

// 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',
                ],
            ],
        ],
    ],

Snippet 2

config/healthcheck.php

    'checks' => [
        UKFast\HealthCheck\Checks\RedisHealthCheck::class,
    ],

Screenshot from postman:

Screenshot 2021-10-01 at 10 47 59

Expected behaviour

The healthcheck should check whether we're using a cluster connection, and ping each master node.

Possible fixes

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:

  • Configuration for this check, could allow the user to choose specific nodes from the configuration.
  • Limit the check to a number of nodes
  • investigate required support for predis (I don't think predis supports clusters at all but i'm not 100%)
<?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 :)

Additional context

~

Surface HealthCheck facade

What is the feature?

We could surface a HealthCheck facade which would allow this package to be useful outside of the /health endpoint.

What benefits will this change bring?

People can add handling based on whether a certain check passes.

Prevents potential issues with unreliable external services.

Additional context

I think the following would be a good way to interact with the facade.

if (HealthCheck::passes('env')) {
    continue;
}

Add StorageHealthCheck

What is the feature?

We should add a StorageHealthCheck to the package.

What benefits will this change bring?

It's a useful part of the core Laravel framework, widely used in different apps.

Additional context

The storage check should support multiple drivers, similar to the CacheHealthCheck.

Add GitHub Actions for CI

What is the feature?

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.

See: ans-group/sdk-php#192

What benefits will this change bring?

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.

Additional context

None.

Unable to authorize users using middleware

What is the issue?

  1. I'm not able to limit access to the /health endpoint using middleware. There's no way to retrieve the user making the request ($request->user() returns null). Am I missing something?
  2. Not sure if it is possible to use middleware with parameters (e.g. role:admin)?

Steps To Reproduce

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.

Zrzut ekranu z 2022-02-01 16-44-27

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.

Expected behaviour

If the user is authenticated, the user object should be accessible so I could make some additional authorization checks.

Additional context

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.

Add CacheHealthCheck

What is the feature?

We should add a CacheHealthCheck to the package.

What benefits will this change bring?

It's a useful part of the core Laravel framework, widely used in different apps.

Additional context

Cache check should support multiple cache stores and not be reliant on a particular implementation.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.