… | |
… | |
2 | |
2 | |
3 | AnyEvent::Watchdog - generic watchdog/program restarter |
3 | AnyEvent::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 | |
12 | This module implements a watchdog that can repeatedly fork the program and |
13 | This module implements a watchdog that can repeatedly fork the program and |
… | |
… | |
21 | program. It will cause weird effects when used from another module, as |
22 | program. It will cause weird effects when used from another module, as |
22 | perl does not expect to be forked inside C<BEGIN> blocks. |
23 | perl does not expect to be forked inside C<BEGIN> blocks. |
23 | |
24 | |
24 | =head1 RECIPES |
25 | =head1 RECIPES |
25 | |
26 | |
26 | Use AnyEvent::Watchdog solely as a convinient on-demand-restarter: |
27 | Use 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 | |
33 | Use AnyEvent::Watchdog to kill the program and exit when the event loop |
35 | Use AnyEvent::Watchdog to kill the program and exit when the event loop |
34 | fails to run for more than two minutes: |
36 | fails 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 | |
38 | Use AnyEvent::Watchdog to automatically restart the program |
40 | Use AnyEvent::Watchdog to automatically kill (but not restart) the program when it fails |
39 | when it fails to handle events for longer than 5 minutes: |
41 | to 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 VARIABLES/FUNCTIONS |
45 | =head1 VARIABLES/FUNCTIONS |
44 | |
46 | |
45 | The module supports the following variables and functions: |
47 | This 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 | |
51 | package AnyEvent::Watchdog; |
60 | package AnyEvent::Watchdog; |
52 | |
61 | |
53 | # load modules we will use later anyways |
62 | # load modules we will use later anyways |
54 | use common::sense; |
63 | use common::sense; |
55 | |
64 | |
56 | use Carp (); |
65 | use Carp (); |
57 | |
66 | |
58 | our $VERSION = '0.9'; |
67 | our $VERSION = '1.0'; |
59 | |
|
|
60 | =item $AnyEvent::Watchdog::ENABLED |
|
|
61 | |
|
|
62 | This is true when the program is running under the regime of |
|
|
63 | AnyEvent::Watchdog. Semi-obviously, you should I<NOT> C<use> or C<require> |
|
|
64 | this module before looking at this variable, and neither should you try |
|
|
65 | to load this module unless in the main program, rather use an idiom like |
|
|
66 | this: |
|
|
67 | |
|
|
68 | $AnyEvent::Watchdog::ENABLED |
|
|
69 | or die "watchdog not enabled..."; |
|
|
70 | AnyEvent::Watchdog::restart (60); # MUST use () |
|
|
71 | |
|
|
72 | Note that if this variable is defined, but false, then AnyEvent::Watchdog |
|
|
73 | is running, but you are in the watchdog process - you probably did |
|
|
74 | something very wrong in this case. |
|
|
75 | |
|
|
76 | =cut |
|
|
77 | |
68 | |
78 | our $PID; # child pid |
69 | our $PID; # child pid |
79 | our $ENABLED = 0; |
70 | our $ENABLED = 0; # also version |
80 | our $AUTORESTART; # actually exit |
71 | our $AUTORESTART; # actually exit |
81 | our $HEARTBEAT; |
|
|
82 | our ($P, $C); |
72 | our ($P, $C); |
83 | |
73 | |
84 | sub poll($) { |
74 | sub poll($) { |
85 | (vec my $v, fileno $P, 1) = 1; |
75 | (vec my $v, fileno $P, 1) = 1; |
86 | CORE::select $v, undef, undef, $_[0] |
76 | CORE::select $v, undef, undef, $_[0] |
… | |
… | |
226 | # parent code |
216 | # parent code |
227 | close $C; |
217 | close $C; |
228 | server; |
218 | server; |
229 | } else { |
219 | } else { |
230 | # child code |
220 | # child code |
231 | $ENABLED = 1; |
221 | $ENABLED = 1; # also version |
232 | |
222 | |
233 | # restore seek offsets |
223 | # restore seek offsets |
234 | while (my ($k, $v) = each %SEEKPOS) { |
224 | while (my ($k, $v) = each %SEEKPOS) { |
235 | open my $fh, "<&$k" or next; |
225 | open my $fh, "<&$k" or next; |
236 | sysseek $fh, $v, 0; |
226 | sysseek $fh, $v, 0; |
… | |
… | |
240 | close $P; |
230 | close $P; |
241 | last; |
231 | last; |
242 | } |
232 | } |
243 | } |
233 | } |
244 | |
234 | |
245 | =item AnyEvent::Watchdog::restart [$timeout] |
|
|
246 | |
|
|
247 | Tells the supervisor to restart the process when it exits, or forcefully |
|
|
248 | after C<$timeout> seconds (minimum 1, maximum 255, default 60). |
|
|
249 | |
|
|
250 | Calls C<exit 0> to exit the process cleanly. |
|
|
251 | |
|
|
252 | =cut |
|
|
253 | |
|
|
254 | sub restart(;$) { |
|
|
255 | my ($timeout) = @_; |
|
|
256 | |
|
|
257 | $timeout = 60 unless defined $timeout; |
|
|
258 | $timeout = 1 if $timeout < 1; |
|
|
259 | $timeout = 255 if $timeout > 255; |
|
|
260 | |
|
|
261 | syswrite $C, "\x01\x02" . chr $timeout; |
|
|
262 | exit 0; |
|
|
263 | } |
|
|
264 | |
|
|
265 | =item AnyEvent::Watchdog::autorestart [$boolean] |
|
|
266 | |
|
|
267 | =item use AnyEvent::Watchdog qw(autorestart[=$boolean]) |
|
|
268 | |
|
|
269 | Enables or disables autorestart (initially disabled, default for |
|
|
270 | C<$boolean> is to enable): By default, the supervisor will exit if the |
|
|
271 | program exits or dies in any way. When enabling autorestart behaviour, |
|
|
272 | then the supervisor will try to restart the program after it dies. |
|
|
273 | |
|
|
274 | Note that the supervisor will never autorestart when the child died with |
|
|
275 | SIGINT or SIGTERM. |
|
|
276 | |
|
|
277 | =cut |
|
|
278 | |
|
|
279 | sub autorestart(;$) { |
|
|
280 | syswrite $C, !@_ || $_[0] ? "\x01" : "\x00"; |
|
|
281 | } |
|
|
282 | |
|
|
283 | =item AnyEvent::Watchdog::heartbeat [$interval] |
|
|
284 | |
|
|
285 | =item use AnyEvent::Watchdog qw(heartbeat[=$interval]) |
|
|
286 | |
|
|
287 | Tells the supervisor to automatically kill the program if it doesn't |
|
|
288 | react for C<$interval> seconds (minium 1, maximum 255, default 60) , then |
|
|
289 | installs an AnyEvent timer the sends a regular heartbeat to the supervisor |
|
|
290 | twice as often. |
|
|
291 | |
|
|
292 | Exit behaviour isn't changed, so if you want a restart instead of an exit, |
|
|
293 | you have to call C<autorestart>. |
|
|
294 | |
|
|
295 | The heartbeat frequency can be changed as often as you want, an interval |
|
|
296 | of C<0> disables the heartbeat check again. |
|
|
297 | |
|
|
298 | =cut |
|
|
299 | |
|
|
300 | sub heartbeat(;$) { |
|
|
301 | my ($interval) = @_; |
|
|
302 | |
|
|
303 | $interval = 60 unless defined $interval; |
|
|
304 | $interval = 1 if $interval < 1; |
|
|
305 | $interval = 255 if $interval > 255; |
|
|
306 | |
|
|
307 | syswrite $C, "\x03" . chr $interval; |
|
|
308 | |
|
|
309 | require AE; |
|
|
310 | $HEARTBEAT = AE::timer (0, $interval * 0.5, sub { |
|
|
311 | syswrite $C, "\x04"; |
|
|
312 | }); |
|
|
313 | } |
|
|
314 | |
|
|
315 | sub import { |
235 | sub import { |
316 | shift; |
236 | shift; |
317 | |
237 | |
318 | for (@_) { |
238 | while (@_) { |
319 | if (/^autorestart(?:=(.*))?$/) { |
239 | my $k = shift; |
320 | autorestart defined $1 ? $1 : 1; |
240 | |
321 | } elsif (/^heartbeat(?:=(.*))?$/) { |
241 | require AnyEvent::Watchdog::Util; |
322 | 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); |
323 | } else { |
247 | } else { |
324 | Carp::croak "AnyEvent::Watchdog: '$_' is not a valid import argument"; |
248 | Carp::croak "AnyEvent::Watchdog: '$_' is not a valid import argument"; |
325 | } |
249 | } |
326 | } |
250 | } |
327 | } |
251 | } |
328 | |
252 | |
329 | =back |
253 | # used by AnyEvent::Watchdog::Util. |
|
|
254 | our $end; |
|
|
255 | END { $end && &$end } |
330 | |
256 | |
331 | =head1 SEE ALSO |
257 | =head1 SEE ALSO |
332 | |
258 | |
333 | L<AnyEvent>. |
259 | L<AnyEvent::Watchdg::Util>, L<AnyEvent>. |
334 | |
260 | |
335 | =head1 AUTHOR |
261 | =head1 AUTHOR |
336 | |
262 | |
337 | Marc Lehmann <schmorp@schmorp.de> |
263 | Marc Lehmann <schmorp@schmorp.de> |
338 | http://home.schmorp.de/ |
264 | http://home.schmorp.de/ |