ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-Watchdog/Watchdog.pm
(Generate patch)

Comparing AnyEvent-Watchdog/Watchdog.pm (file contents):
Revision 1.3 by root, Thu Aug 13 22:56:11 2009 UTC vs.
Revision 1.10 by root, Thu Apr 28 16:16:37 2022 UTC

2 2
3AnyEvent::Watchdog - generic watchdog/program restarter 3AnyEvent::Watchdog - generic watchdog/program restarter
4 4
5=head1 SYNOPSIS 5=head1 SYNOPSIS
6 6
7 # MUST be use'd as the very first thing in the main program 7 # MUST be use'd as the very first thing in the main program,
8 # as it clones/forks the program before it returns.
8 use AnyEvent::Watchdog; 9 use AnyEvent::Watchdog;
9 10
10=head1 DESCRIPTION 11=head1 DESCRIPTION
11 12
12This module implements a watchdog that can repeatedly fork the program and 13This module implements a watchdog that can repeatedly fork the program and
21program. It will cause weird effects when used from another module, as 22program. It will cause weird effects when used from another module, as
22perl does not expect to be forked inside C<BEGIN> blocks. 23perl does not expect to be forked inside C<BEGIN> blocks.
23 24
24=head1 RECIPES 25=head1 RECIPES
25 26
26Use AnyEvent::Watchdog solely as a convinient on-demand-restarter: 27Use AnyEvent::Watchdog solely as a convenient on-demand-restarter:
27 28
28 use AnyEvent::Watchdog; 29 use AnyEvent::Watchdog;
29 30
30 # and whenever you wnat to restart (e.g. to upgrade code): 31 # and whenever you want to restart (e.g. to upgrade code):
32 use AnyEvent::Watchdog::Util;
31 AnyEvent::Watchdog::restart; 33 AnyEvent::Watchdog::Util::restart;
32 34
33Use AnyEvent::Watchdog to kill the program and exit when the event loop 35Use AnyEvent::Watchdog to kill the program and exit when the event loop
34fails to run for more than two minutes: 36fails to run for more than two minutes:
35 37
36 use AnyEvent::Watchdog qw(autorestart heartbeat=120); 38 use AnyEvent::Watchdog autorestart => 1, heartbeat => 120;
37 39
38Use AnyEvent::Watchdog to automatically restart the program 40Use AnyEvent::Watchdog to automatically kill (but not restart) the program when it fails
39when it fails to handle events for longer than 5 minutes: 41to handle events for longer than 5 minutes:
40 42
41 use AnyEvent::Watchdog qw(autorestart heartbeat=300); 43 use AnyEvent::Watchdog heartbeat => 300;
42 44
43=head1 FUNCTIONS 45=head1 VARIABLES/FUNCTIONS
44 46
45The module supports the following functions: 47This module is controlled via the L<AnyEvent::Watchdog::Util> module:
46 48
47=over 4 49 use AnyEvent::Watchdog::Util;
50
51 # attempt restart
52 AnyEvent::Watchdog::Util::restart;
53
54 # check if it is running
55 AnyEvent::Watchdog::Util::enabled
56 or croak "not running under watchdog!";
48 57
49=cut 58=cut
50 59
51package AnyEvent::Watchdog; 60package AnyEvent::Watchdog;
52 61
53# load modules we will use later anyways 62# load modules we will use later anyways
54use common::sense; 63use common::sense;
55 64
56use Carp (); 65use Carp ();
57 66
58our $VERSION = '0.1'; 67our $VERSION = '1.02';
59 68
60our $PID; # child pid 69our $PID; # child pid
61our $ENABLED = 1; 70our $ENABLED = 0; # also version
62our $AUTORESTART; # actually exit 71our $AUTORESTART; # actually exit
63our $HEARTBEAT;
64our ($P, $C); 72our ($P, $C);
65 73
66sub poll($) { 74sub poll($) {
67 (vec my $v, fileno $P, 1) = 1; 75 (vec my $v, fileno $P, 1) = 1;
68 CORE::select $v, undef, undef, $_[0] 76 CORE::select $v, undef, undef, $_[0]
164 172
165our %SEEKPOS; 173our %SEEKPOS;
166# due to bugs in perl, try to remember file offsets for all fds, and restore them later 174# due to bugs in perl, try to remember file offsets for all fds, and restore them later
167# (the parser otherwise exhausts the input files) 175# (the parser otherwise exhausts the input files)
168 176
169# this causes perlio to flush it's handles internally, so 177# this causes perlio to flush its handles internally, so
170# seek offsets become correct. 178# seek offsets become correct.
171exec "."; # toi toi toi 179exec "."; # toi toi toi
172#{ 180#{
173# local $SIG{CHLD} = 'DEFAULT'; 181# local $SIG{CHLD} = 'DEFAULT';
174# my $pid = fork; 182# my $pid = fork;
178# } else { 186# } else {
179# kill 9, $$; 187# kill 9, $$;
180# } 188# }
181#} 189#}
182 190
183# now records all fd positions 191# now record "all" fd positions, assuming 1023 is more than enough.
184for (0 .. 1023) { 192for (0 .. 1023) {
185 open my $fh, "<&$_" or next; 193 open my $fh, "<&$_" or next;
186 $SEEKPOS{$_} = (sysseek $fh, 0, 1 or next); 194 $SEEKPOS{$_} = (sysseek $fh, 0, 1 or next);
187} 195}
188 196
203 211
204 unless (defined $PID) { 212 unless (defined $PID) {
205 warn "AnyEvent::Watchdog: '$!', retrying in one second...\n"; 213 warn "AnyEvent::Watchdog: '$!', retrying in one second...\n";
206 sleep 1; 214 sleep 1;
207 } elsif ($PID) { 215 } elsif ($PID) {
216 # parent code
208 close $C; 217 close $C;
209 server; 218 server;
210 } else { 219 } else {
220 # child code
221 $ENABLED = 1; # also version
222
211 # restore seek offsets 223 # restore seek offsets
212 while (my ($k, $v) = each %SEEKPOS) { 224 while (my ($k, $v) = each %SEEKPOS) {
213 open my $fh, "<&$k" or next; 225 open my $fh, "<&$k" or next;
214 sysseek $fh, $v, 0; 226 sysseek $fh, $v, 0;
215 } 227 }
218 close $P; 230 close $P;
219 last; 231 last;
220 } 232 }
221} 233}
222 234
223=item AnyEvent::Watchdog::restart [$timeout]
224
225Tells the supervisor to restart the process when it exits, or forcefully
226after C<$timeout> seconds (minimum 1, maximum 255, default 60).
227
228Calls C<exit 0> to exit the process cleanly.
229
230=cut
231
232sub restart(;$) {
233 my ($timeout) = @_;
234
235 $timeout = 60 unless defined $timeout;
236 $timeout = 1 if $timeout < 1;
237 $timeout = 255 if $timeout > 255;
238
239 syswrite $C, "\x01\x02" . chr $timeout;
240 exit 0;
241}
242
243=item AnyEvent::Watchdog::autorestart [$boolean]
244
245=item use AnyEvent::Watchdog qw(autorestart[=$boolean])
246
247Enables or disables autorestart (initially disabled, default for
248C<$boolean> is to enable): By default, the supervisor will exit if the
249program exits or dies in any way. When enabling autorestart behaviour,
250then the supervisor will try to restart the program after it dies.
251
252Note that the supervisor will never autorestart when the child died with
253SIGINT or SIGTERM.
254
255=cut
256
257sub autorestart(;$) {
258 syswrite $C, !@_ || $_[0] ? "\x01" : "\x00";
259}
260
261=item AnyEvent::Watchdog::heartbeat [$interval]
262
263=item use AnyEvent::Watchdog qw(heartbeat[=$interval])
264
265Tells the supervisor to automatically kill the program if it doesn't
266react for C<$interval> seconds (minium 1, maximum 255, default 60) , then
267installs an AnyEvent timer the sends a regular heartbeat to the supervisor
268twice as often.
269
270Exit behaviour isn't changed, so if you want a restart instead of an exit,
271you have to call C<autorestart>.
272
273The heartbeat frequency can be changed as often as you want, an interval
274of C<0> disables the heartbeat check again.
275
276=cut
277
278sub heartbeat(;$) {
279 my ($interval) = @_;
280
281 $interval = 60 unless defined $interval;
282 $interval = 1 if $interval < 1;
283 $interval = 255 if $interval > 255;
284
285 syswrite $C, "\x03" . chr $interval;
286
287 require AE;
288 $HEARTBEAT = AE::timer (0, $interval * 0.5, sub {
289 syswrite $C, "\x04";
290 });
291}
292
293sub import { 235sub import {
294 shift; 236 shift;
295 237
296 for (@_) { 238 while (@_) {
297 if (/^autorestart(?:=(.*))?$/) { 239 my $k = shift;
298 autorestart defined $1 ? $1 : 1; 240
299 } elsif (/^heartbeat(?:=(.*))?$/) { 241 require AnyEvent::Watchdog::Util;
300 heartbeat $1; 242
243 if ($k eq "autorestart") {
244 AnyEvent::Watchdog::Util::autorestart (! ! shift);
245 } elsif ($k eq "heartbeat") {
246 AnyEvent::Watchdog::Util::heartbeat (shift || 60);
301 } else { 247 } else {
302 Carp::croak "AnyEvent::Watchdog: '$_' is not a valid import argument"; 248 Carp::croak "AnyEvent::Watchdog: '$_' is not a valid import argument";
303 } 249 }
304 } 250 }
305} 251}
306 252
307=back 253# used by AnyEvent::Watchdog::Util.
254our $end;
255END { $end && &$end }
308 256
309=head1 SEE ALSO 257=head1 SEE ALSO
310 258
311L<AnyEvent>. 259L<AnyEvent::Watchdog::Util>, L<AnyEvent>.
312 260
313=head1 AUTHOR 261=head1 AUTHOR
314 262
315 Marc Lehmann <schmorp@schmorp.de> 263 Marc Lehmann <schmorp@schmorp.de>
316 http://home.schmorp.de/ 264 http://home.schmorp.de/

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines