File Coverage

blib/lib/Dancer2/Plugin/Role/Shutdown.pm
Criterion Covered Total %
statement 55 61 90.1
branch 13 22 59.0
condition 7 14 50.0
subroutine 11 11 100.0
pod 3 3 100.0
total 89 111 80.1


line stmt bran cond sub pod time code
1 1     1   463 use strictures 2;
  1         5  
  1         33  
2              
3             package # for internal use only
4             Dancer2::Plugin::Role::Shutdown;
5              
6             # ABSTRACT: Role for L
7              
8 1     1   140 use Carp qw(croak);
  1         1  
  1         40  
9 1     1   3 use Class::Load qw(load_class);
  1         1  
  1         35  
10 1     1   3 use Scalar::Util qw(blessed);
  1         1  
  1         40  
11 1     1   3 use Moo::Role 2;
  1         16  
  1         4  
12              
13 1     1   201 use constant NORMAL => 0;
  1         1  
  1         70  
14 1     1   3 use constant GRACEFUL => 1;
  1         1  
  1         462  
15              
16             our $VERSION = '0.002'; # VERSION
17              
18              
19             has shared => (
20             is => 'rwp',
21             default => sub { {} },
22             );
23              
24              
25             has validator => (
26             is => 'rw',
27             default => sub {
28             sub {
29             my ($app, $rest, $sessid) = @_;
30             return unless $sessid;
31             my $sx = $app->session->expires // 0;
32             $app->session->expires($rest) if $rest > $sx;
33             $app->response->header(Warning => "199 Application shuts down in $rest seconds");
34             return 1;
35             }
36             }
37             );
38              
39              
40             sub has_valid_session {
41 5     5 1 239 my $app = shift;
42              
43 5   50     76 my $engine = $app->session_engine // return;
44              
45 5 50       42 return if $app->has_destroyed_session;
46              
47 5   100     23 my $session_cookie = $app->cookie( $engine->cookie_name ) // return;
48 3   50     1090 my $session_id = $session_cookie->value // return;
49              
50 3         115 eval { $engine->retrieve( id => $session_id ) };
  3         16  
51 3 50       901 return if $@;
52              
53 3         9 return $session_id;
54             }
55              
56              
57             sub session_status {
58 1     1 1 166 my $app = shift;
59              
60 1   50     17 my $engine = $app->session_engine // return "unsupported";
61              
62 1 50       9 return "destroyed" if $app->has_destroyed_session;
63              
64 1   50     4 my $session_cookie = $app->cookie( $engine->cookie_name ) // return "missing";
65 0   0     0 my $session_id = $session_cookie->value // return "empty";
66              
67 0         0 eval { $engine->retrieve( id => $session_id ) };
  0         0  
68 0 0       0 return "invalid" if $@;
69              
70 0         0 return "ok";
71             }
72              
73              
74             sub before_hook {
75 7     7 1 14 my $self = shift;
76 7 100       48 return unless $self->shared->{state};
77 3         10 my $app = $self->app;
78 3         8 my $time = $self->shared->{final};
79 3         6 my $rest = $time - time;
80 3 100       13 if ($rest < 0) {
    50          
81 1         5 $self->status(503);
82 1         88 $self->halt;
83             } elsif ($self->shared->{state} == GRACEFUL) {
84 2 50       12 if (my $validator = $self->validator) {
85 2         25 my $sessid = has_valid_session($app);
86 2 100       120 unless ($validator->($app, $rest, $sessid)) {
87 1         23 $self->status(503);
88 1         93 $self->halt;
89             }
90             }
91             } else {
92 0         0 croak "bad state: ".$self->shared->{state};
93             }
94             }
95              
96             sub _shutdown_at {
97 1     1   82 my $self = shift;
98 1 50       21 croak "a validator isn't installed yet" unless ref $self->validator eq 'CODE';
99 1   50     4 my $time = shift // 0;
100 1 50       5 if ($time < time) {
101 1         3 $time += time;
102             }
103 1         5 $self->shared->{final} = $time;
104 1         3 $self->shared->{state} = GRACEFUL;
105 1         3 return $time;
106             }
107              
108             1;
109              
110             __END__