Lines 100.00% 10 / 10
Functions and Methods 100.00% 2 / 2
Classes and Traits 100.00% 1 / 1
Name Lines Functions and Methods CRAP Classes and Traits
ProbeRequestHandler 100.00% 10 / 10 100.00% 2 / 2 5 100.00% 1 / 1
 __construct 100.00% 1 / 1 100.00% 1 / 1 1
 handleRequest 100.00% 9 / 9 100.00% 1 / 1 4
1<?php
2
3declare(strict_types=1);
4
5namespace Stewart\Runtime\Http;
6
7use Amp\Http\HttpStatus;
8use Amp\Http\Server\Request;
9use Amp\Http\Server\RequestHandler;
10use Amp\Http\Server\Response;
11use Psr\Log\LoggerInterface;
12use Stewart\Runtime\Health\ProbeKind;
13use Stewart\Runtime\Health\ProbeReportCodec;
14use Stewart\Runtime\Health\ProbeReporter;
15use Throwable;
16
17final readonly class ProbeRequestHandler implements RequestHandler
18{
19    private const array PROBE_PATHS = ['/healthz' => ProbeKind::Liveness, '/readyz' => ProbeKind::Readiness];
20
21    private const array REPORT_HEADERS = ['content-type' => 'application/json', 'cache-control' => 'no-store'];
22
23    public function __construct(
24        private ProbeReporter $reporter,
25        private ProbeReportCodec $codec,
26        private LoggerInterface $logger,
27    ) {}
28
29    public function handleRequest(Request $request): Response
30    {
31        $kind = self::PROBE_PATHS[$request->getUri()->getPath()] ?? null;
32
33        if ($kind === null) {
34            return new Response(HttpStatus::NOT_FOUND);
35        }
36
37        try {
38            $report = $this->reporter->reportProbe($kind);
39            $body = $this->codec->encodeReport($report);
40        } catch (Throwable $e) {
41            $this->logger->error('Could not answer the probe', ['probe' => $kind->value, 'exception' => $e]);
42
43            return new Response(HttpStatus::INTERNAL_SERVER_ERROR);
44        }
45
46        return new Response($report->status->isHealthy() ? HttpStatus::OK : HttpStatus::SERVICE_UNAVAILABLE, self::REPORT_HEADERS, $body);
47    }
48}