… | |
… | |
38 | Use AnyEvent::Watchdog to automatically restart the program |
38 | Use AnyEvent::Watchdog to automatically restart the program |
39 | when it fails to handle events for longer than 5 minutes: |
39 | when it fails to handle events for longer than 5 minutes: |
40 | |
40 | |
41 | use AnyEvent::Watchdog qw(autorestart heartbeat=300); |
41 | use AnyEvent::Watchdog qw(autorestart heartbeat=300); |
42 | |
42 | |
43 | =head1 FUNCTIONS |
43 | =head1 VARIABLES/FUNCTIONS |
44 | |
44 | |
45 | The module supports the following functions: |
45 | The module supports the following variables and functions: |
46 | |
46 | |
47 | =over 4 |
47 | =over 4 |
48 | |
48 | |
49 | =cut |
49 | =cut |
50 | |
50 | |
… | |
… | |
53 | # load modules we will use later anyways |
53 | # load modules we will use later anyways |
54 | use common::sense; |
54 | use common::sense; |
55 | |
55 | |
56 | use Carp (); |
56 | use Carp (); |
57 | |
57 | |
58 | our $VERSION = '0.1'; |
58 | our $VERSION = '0.9'; |
|
|
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 |
59 | |
77 | |
60 | our $PID; # child pid |
78 | our $PID; # child pid |
61 | our $ENABLED = 1; |
79 | our $ENABLED = 0; |
62 | our $AUTORESTART; # actually exit |
80 | our $AUTORESTART; # actually exit |
63 | our $HEARTBEAT; |
81 | our $HEARTBEAT; |
64 | our ($P, $C); |
82 | our ($P, $C); |
65 | |
83 | |
66 | sub poll($) { |
84 | sub poll($) { |
… | |
… | |
118 | |
136 | |
119 | } elsif ($cmd eq chr 3) { |
137 | } elsif ($cmd eq chr 3) { |
120 | sysread $P, my $interval, 1 |
138 | sysread $P, my $interval, 1 |
121 | or last; |
139 | or last; |
122 | |
140 | |
123 | $heartbeat = ord $interval |
141 | $heartbeat = ord $interval; |
124 | unless defined $heartbeat; |
|
|
125 | |
142 | |
126 | } elsif ($cmd eq chr 4) { |
143 | } elsif ($cmd eq chr 4) { |
127 | # heartbeat |
144 | # heartbeat |
128 | # TODO: should only reset heartbeat timeout with \005 |
145 | # TODO: should only reset heartbeat timeout with \005 |
129 | |
146 | |
… | |
… | |
165 | |
182 | |
166 | our %SEEKPOS; |
183 | our %SEEKPOS; |
167 | # due to bugs in perl, try to remember file offsets for all fds, and restore them later |
184 | # due to bugs in perl, try to remember file offsets for all fds, and restore them later |
168 | # (the parser otherwise exhausts the input files) |
185 | # (the parser otherwise exhausts the input files) |
169 | |
186 | |
170 | # this causes perlio to flush it's handles internally, so |
187 | # this causes perlio to flush its handles internally, so |
171 | # seek offsets become correct. |
188 | # seek offsets become correct. |
172 | exec "."; # toi toi toi |
189 | exec "."; # toi toi toi |
173 | #{ |
190 | #{ |
174 | # local $SIG{CHLD} = 'DEFAULT'; |
191 | # local $SIG{CHLD} = 'DEFAULT'; |
175 | # my $pid = fork; |
192 | # my $pid = fork; |
… | |
… | |
179 | # } else { |
196 | # } else { |
180 | # kill 9, $$; |
197 | # kill 9, $$; |
181 | # } |
198 | # } |
182 | #} |
199 | #} |
183 | |
200 | |
184 | # now records all fd positions |
201 | # now record "all" fd positions, assuming 1023 is more than enough. |
185 | for (0 .. 1023) { |
202 | for (0 .. 1023) { |
186 | open my $fh, "<&$_" or next; |
203 | open my $fh, "<&$_" or next; |
187 | $SEEKPOS{$_} = (sysseek $fh, 0, 1 or next); |
204 | $SEEKPOS{$_} = (sysseek $fh, 0, 1 or next); |
188 | } |
205 | } |
189 | |
206 | |
… | |
… | |
204 | |
221 | |
205 | unless (defined $PID) { |
222 | unless (defined $PID) { |
206 | warn "AnyEvent::Watchdog: '$!', retrying in one second...\n"; |
223 | warn "AnyEvent::Watchdog: '$!', retrying in one second...\n"; |
207 | sleep 1; |
224 | sleep 1; |
208 | } elsif ($PID) { |
225 | } elsif ($PID) { |
|
|
226 | # parent code |
209 | close $C; |
227 | close $C; |
210 | server; |
228 | server; |
211 | } else { |
229 | } else { |
|
|
230 | # child code |
|
|
231 | $ENABLED = 1; |
|
|
232 | |
212 | # restore seek offsets |
233 | # restore seek offsets |
213 | while (my ($k, $v) = each %SEEKPOS) { |
234 | while (my ($k, $v) = each %SEEKPOS) { |
214 | open my $fh, "<&$k" or next; |
235 | open my $fh, "<&$k" or next; |
215 | sysseek $fh, $v, 0; |
236 | sysseek $fh, $v, 0; |
216 | } |
237 | } |
… | |
… | |
269 | twice as often. |
290 | twice as often. |
270 | |
291 | |
271 | Exit behaviour isn't changed, so if you want a restart instead of an exit, |
292 | Exit behaviour isn't changed, so if you want a restart instead of an exit, |
272 | you have to call C<autorestart>. |
293 | you have to call C<autorestart>. |
273 | |
294 | |
274 | Once enabled, the heartbeat cannot be switched off. |
295 | The heartbeat frequency can be changed as often as you want, an interval |
|
|
296 | of C<0> disables the heartbeat check again. |
275 | |
297 | |
276 | =cut |
298 | =cut |
277 | |
299 | |
278 | sub heartbeat(;$) { |
300 | sub heartbeat(;$) { |
279 | my ($interval) = @_; |
301 | my ($interval) = @_; |
… | |
… | |
302 | Carp::croak "AnyEvent::Watchdog: '$_' is not a valid import argument"; |
324 | Carp::croak "AnyEvent::Watchdog: '$_' is not a valid import argument"; |
303 | } |
325 | } |
304 | } |
326 | } |
305 | } |
327 | } |
306 | |
328 | |
|
|
329 | =back |
|
|
330 | |
307 | =head1 SEE ALSO |
331 | =head1 SEE ALSO |
308 | |
332 | |
309 | L<AnyEvent>. |
333 | L<AnyEvent>. |
310 | |
334 | |
311 | =head1 AUTHOR |
335 | =head1 AUTHOR |