File Coverage

blib/lib/IO/Async/Process/GracefulShutdown.pm
Criterion Covered Total %
statement 26 26 100.0
branch 1 2 50.0
condition 4 4 100.0
subroutine 8 8 100.0
pod 1 1 100.0
total 40 41 97.5


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2019 -- leonerd@leonerd.org.uk
5              
6             package IO::Async::Process::GracefulShutdown;
7              
8 3     3   121550 use strict;
  3         23  
  3         70  
9 3     3   12 use warnings;
  3         5  
  3         67  
10 3     3   56 use 5.010; # //
  3         8  
11 3     3   14 use base qw( IO::Async::Process );
  3         4  
  3         1598  
12             IO::Async::Process->VERSION( '0.75' ); # ->finish_future
13              
14             our $VERSION = '0.02';
15              
16             =head1 NAME
17              
18             C - controlled shutdown of a process
19              
20             =head1 SYNOPSIS
21              
22             use IO::Async::Process::GracefulShutdown;
23              
24             use IO::Async::Loop;
25             my $loop = IO::Async::Loop;
26              
27             my $process = IO::Async::Process::GracefulShutdown->new(
28             command => [ "my-proc" ],
29             );
30              
31             $loop->add( $process );
32              
33             ...
34              
35             $process->shutdown( "TERM" )->get;
36              
37             =head1 DESCRIPTION
38              
39             This subclass of L adds a method to perform a shutdown of
40             the invoked process by sending a signal. If after some delay the process has
41             not yet exited, it is sent a C instead.
42              
43             =cut
44              
45             sub _init
46             {
47 4     4   56718 my $self = shift;
48 4         13 my ( $params ) = @_;
49              
50 4   100 3   57 $params->{on_finish} //= sub {}; # back-compat did not require this
51              
52 4         31 $self->SUPER::_init( $params );
53             }
54              
55             =head1 METHODS
56              
57             =cut
58              
59             =head2 shutdown
60              
61             $process->shutdown( $signal, %args )->get
62              
63             Requests the process shut down by sending it the given signal (either
64             specified by name or number). If the process does not shut down after a
65             timeout, C is sent instead.
66              
67             The returned future will complete when the process exits.
68              
69             Takes the following named arguments:
70              
71             =over 4
72              
73             =item timeout => NUM
74              
75             Optional. Number of seconds to wait for exit before sending C.
76             Defaults to 10 seconds.
77              
78             =item on_kill => CODE
79              
80             Optional. Callback to invoke if the timeout occurs and C is going to
81             be sent. Intended for printing or logging purposes; this doesn't have any
82             material effect on the process otherwise.
83              
84             $on_kill->( $process )
85              
86             =back
87              
88             =cut
89              
90             sub shutdown
91             {
92 2     2 1 31832 my $self = shift;
93 2         50 my ( $signal, %args ) = @_;
94              
95 2   100     40 my $timeout = $args{timeout} // 10;
96              
97 2         23 my $pid = $self->pid;
98              
99 2         62 $self->debug_printf( "KILL signal=%s", $signal );
100 2         58 $self->kill( $signal );
101              
102             return Future->needs_any(
103             $self->finish_future->then_done(),
104              
105             $self->loop->delay_future( after => $timeout )->then(
106             sub {
107 1 50   1   101720 $args{on_kill}->( $self ) if $args{on_kill};
108              
109 1         27 $self->debug_printf( "KILL signal=KILL" );
110 1         17 $self->kill( "KILL" );
111 1         78 Future->done;
112             })
113 2         90 );
114             }
115              
116             =head1 AUTHOR
117              
118             Paul Evans
119              
120             =cut
121              
122             0x55AA;