File Coverage

blib/lib/Ubic/Service/Hypnotoad.pm
Criterion Covered Total %
statement 21 89 23.6
branch 0 38 0.0
condition 0 22 0.0
subroutine 7 16 43.7
pod 5 6 83.3
total 33 171 19.3


line stmt bran cond sub pod time code
1             package Ubic::Service::Hypnotoad;
2             # ABSTRACT: Ubic service module for Mojolicious Hypnotoad
3             $Ubic::Service::Hypnotoad::VERSION = '0.3';
4 1     1   13232 use strict;
  1         2  
  1         31  
5 1     1   4 use warnings;
  1         1  
  1         27  
6              
7 1     1   362 use parent qw(Ubic::Service::Skeleton);
  1         225  
  1         4  
8              
9 1     1   18143 use Ubic::Result qw(result);
  1         1  
  1         30  
10 1     1   4 use File::Basename;
  1         1  
  1         56  
11 1     1   3 use Time::HiRes qw(time);
  1         1  
  1         5  
12 1     1   533 use Capture::Tiny qw(:all);
  1         17445  
  1         824  
13              
14              
15              
16              
17             sub new {
18 0     0 0   my ($class, $opt) = @_;
19              
20 0 0 0       my $bin = [split /\s+/, ($opt->{'bin'} // 'hypnotoad')] unless ref $opt->{bin} eq 'ARRAY';
21 0 0         @$bin or die "missing 'bin' parameter in new";
22 0   0       my $app = $opt->{'app'} // '';
23 0 0         length $app or die "missing 'app' parameter in new";
24 0   0       my $pid_file = $opt->{'pid_file'} // dirname($app).'/hypnotoad.pid';
25 0 0         length $pid_file or die "missing 'pid_file' parameter in new";
26              
27 0   0       my %env = %{ $opt->{'env'} // {} };
  0            
28              
29 0           my $wait_status = _calc_wait_status($opt->{wait_status});
30              
31 0           return bless {
32             bin => $bin,
33             app => $app,
34             env => \%env,
35             pid_file => $pid_file,
36             start_time => undef,
37             stop_time => undef,
38             cwd => $opt->{cwd},
39             wait_status => $wait_status,
40             }, $class;
41             }
42              
43             sub _calc_wait_status {
44 0     0     my $wait_status = shift;
45 0   0       my $step = $wait_status->{step} // 0.1;
46 0   0       my $trials = $wait_status->{trials} // 10;
47              
48 0           my $time_to_wait = $step * ($trials - 1) * $trials / 2 + 1;
49              
50             return {
51 0           step => $step,
52             trials => $trials,
53             time_to_wait => $time_to_wait,
54             };
55             }
56              
57             sub _read_pid {
58 0     0     my $self = shift;
59              
60 0           return eval {
61 0 0         open my $fh, $self->{'pid_file'} or die;
62 0           my $pid = (scalar(<$fh>) =~ /(\d+)/g)[0];
63 0           close $fh;
64 0           $pid;
65             };
66             }
67              
68             sub status_impl {
69 0     0 1   my $self = shift;
70              
71 0           my $pid = $self->_read_pid;
72              
73 0 0 0       if ($self->{'start_time'} and $self->{'start_time'} + $self->{wait_status}{time_to_wait} > time) {
74 0 0         return result('broken') if ! $pid;
75             }
76 0           $self->{'start_time'} = undef;
77              
78 0 0         if (! $pid) {
79 0           $self->{'stop_time'} = undef;
80 0           return result('not running');
81             }
82              
83 0 0 0       if ($self->{'stop_time'} and $self->{'stop_time'} + $self->{wait_status}{time_to_wait} > time) {
84 0           return result('broken');
85             }
86              
87 0           my ($i, $running, $old_pid) = (0);
88 0   0       do {
89 0           $i++;
90 0           $old_pid = $pid;
91 0           $running = kill 0, $old_pid;
92 0 0         $pid = $self->_read_pid or return result('not running');
93             } until ($pid == $old_pid or $i > 5);
94              
95 0 0         $pid == $old_pid or return result('broken');
96              
97 0 0         return $running ? result('running', 'pid '.$pid) : result('not running');
98             }
99              
100             sub start_impl {
101 0     0 1   my $self = shift;
102              
103 0           local %ENV = (%ENV, %{ $self->{'env'} });
  0            
104              
105 0 0         if (defined $self->{cwd}) {
106 0 0         chdir $self->{cwd} or die "chdir to '$self->{cwd}' failed: $!";
107             }
108              
109 0           system(@{$self->{'bin'}}, $self->{'app'});
  0            
110 0           $self->{'start_time'} = time;
111 0           $self->{'stop_time'} = undef;
112              
113 0           return result('starting');
114             }
115              
116             sub stop_impl {
117 0     0 1   my $self = shift;
118              
119 0 0         if (defined $self->{cwd}) {
120 0 0         chdir $self->{cwd} or die "chdir to '$self->{cwd}' failed: $!";
121             }
122              
123 0           local %ENV = (%ENV, %{ $self->{'env'} });
  0            
124             my (undef, $stderr) = capture {
125 0     0     system(@{$self->{'bin'}}, '-s', $self->{'app'});
  0            
126 0           };
127 0 0         print $stderr if length $stderr;
128 0           $self->{'stop_time'} = time;
129 0           $self->{'start_time'} = undef;
130              
131 0           return result('stopping');
132             }
133              
134             sub reload {
135 0     0 1   my $self = shift;
136              
137 0 0         my $pid = $self->_read_pid or return 'not running';
138 0           my $ret = kill "USR2", $pid;
139 0 0         return $ret ? 'reloaded' : 'not running';
140             }
141              
142             sub timeout_options {
143 0     0 1   my $self = shift;
144              
145             return {
146 0           start => {
147             step => $self->{wait_status}{step},
148             trials => $self->{wait_status}{trials},
149             },
150             stop => {
151             step => $self->{wait_status}{step},
152             trials => $self->{wait_status}{trials},
153             }
154             };
155             }
156              
157              
158              
159              
160              
161             1;
162              
163             __END__