File Coverage

lib/PAGI/App/Healthcheck.pm
Criterion Covered Total %
statement 41 41 100.0
branch 14 14 100.0
condition 2 2 100.0
subroutine 7 7 100.0
pod 0 2 0.0
total 64 66 96.9


line stmt bran cond sub pod time code
1             package PAGI::App::Healthcheck;
2              
3 1     1   219956 use strict;
  1         1  
  1         36  
4 1     1   5 use warnings;
  1         1  
  1         36  
5 1     1   4 use Future::AsyncAwait;
  1         2  
  1         7  
6 1     1   59 use JSON::MaybeXS ();
  1         1  
  1         632  
7              
8             =head1 NAME
9              
10             PAGI::App::Healthcheck - Health check endpoint app
11              
12             =head1 SYNOPSIS
13              
14             use PAGI::App::Healthcheck;
15              
16             my $app = PAGI::App::Healthcheck->new(
17             checks => {
18             database => sub { check_db() },
19             },
20             )->to_app;
21              
22             =cut
23              
24             our $START_TIME = time();
25              
26             sub new {
27 5     5 0 194251 my ($class, %args) = @_;
28              
29             return bless {
30             checks => $args{checks} // {},
31             version => $args{version},
32 5   100     35 }, $class;
33             }
34              
35             sub to_app {
36 5     5 0 6 my ($self) = @_;
37              
38 5         8 my $checks = $self->{checks};
39 5         5 my $version = $self->{version};
40              
41 5     5   72 return async sub {
42 5         7 my ($scope, $receive, $send) = @_;
43 5         9 my $all_ok = 1;
44 5         4 my %results;
45              
46 5         21 for my $name (sort keys %$checks) {
47 4         4 my $check = $checks->{$name};
48 4         8 my $result = { status => 'ok' };
49              
50 4 100       3 eval { my $ok = $check->(); $result->{status} = 'error' unless $ok; };
  4         6  
  3         9  
51 4 100       13 if ($@) {
52 1         2 $result->{status} = 'error';
53 1         2 $result->{message} = "$@";
54 1         7 $result->{message} =~ s/\s+$//;
55             }
56              
57 4         4 $results{$name} = $result;
58 4 100       9 $all_ok = 0 if $result->{status} eq 'error';
59             }
60              
61 5 100       19 my $response = {
62             status => $all_ok ? 'ok' : 'error',
63             timestamp => time(),
64             uptime => time() - $START_TIME,
65             };
66 5 100       9 $response->{version} = $version if defined $version;
67 5 100       8 $response->{checks} = \%results if %results;
68              
69 5         35 my $body = JSON::MaybeXS::encode_json($response);
70 5 100       6 my $status = $all_ok ? 200 : 503;
71              
72 5         28 await $send->({
73             type => 'http.response.start',
74             status => $status,
75             headers => [
76             ['content-type', 'application/json'],
77             ['content-length', length($body)],
78             ['cache-control', 'no-cache'],
79             ],
80             });
81 5         280 await $send->({ type => 'http.response.body', body => $body, more => 0 });
82 5         22 };
83             }
84              
85             1;
86              
87             __END__