Useful Health Check Endpoints in PHP Applications

At PMG we run pretty much every application in AWS’s Elastic Container Service with web entrypoint handled by Application Loader Balancers.

One feature of the ALB and ECS is that web-based services do a blue/green deployment. When a new version of the application is shipped, it spins up a new container in the ECS cluster and the load balancer starts hitting a health check endpoint on the new service. Once a few successful health checks are made, the load balancer considers the container healthy and starts sending traffic to it. After that old containers are spun down.

I struggled quite a bit with the health check endpoint in our applications. Tradditionally a health check endpoint checks everything. Is the database up? Is redis running? If any part of the stack is broken, the app is unhealthy.

That’s not a bad approach, but I didn’t want a load balancer marking web containers as unhealthy because of a database issue. New containers coming up wouldn’t fix an unhealthy state caused by a backing service. I would rather handle service unavailable (503) errors caused by backing services in the application layer itself — not the load balancer.

So what’s a useful health check for a load balancer to hit? One that runs through the entire PHP application layer without touching any backing services. So ideally something that doesn’t touch any backing services but runs through your framework’s routing and templating components.

In Symfony this is a controller that renders an `OK` text template or something similar.

use Symfony\Component\HttpFoundation\Response;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

class HealthController extends AbstractController
{
  public function health() : Response
  {
    $response = new Response('', 200, ['Content-Type' => 'text/plain']);
    return $this->render('health.txt.twig', [], $response);
  }
}

This will effectively check that the integration and configuration with the framework itself is okay. That’s enough to allow a container or server to be “healthy” and start receiving traffic from a load balancer.

Why render a template? It’s not necessary if the application isn’t using twig in any other way, but for applications that do use twig it’s important to check that the integration with twig (or another templating engine) is correct. I learned this the hard when when I upgraded an application to Symfony 4.X and moved the templates directory then forgot to include the new path in my docker build.