ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-Watchdog/Watchdog/Util.pm
Revision: 1.2
Committed: Tue Sep 1 14:53:19 2009 UTC (15 years, 1 month ago) by root
Branch: MAIN
Changes since 1.1: +0 -5 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 =head1 NAME
2
3 AnyEvent::Watchdog::Util - watchdog control and process management
4
5 =head1 SYNOPSIS
6
7 use AnyEvent::Watchdog::Util;
8
9 =head1 DESCRIPTION
10
11 This module can control the watchdog started by using
12 L<AnyEvent::Watchdog> in your main program, but it has useful
13 functionality even when not running under the watchdog at all, such as
14 program exit hooks.
15
16 =head1 VARIABLES/FUNCTIONS
17
18 The module supports the following variables and functions:
19
20 =over 4
21
22 =cut
23
24 package AnyEvent::Watchdog::Util;
25
26 # load modules we will use later anyways
27 use common::sense;
28 use AnyEvent ();
29 use Carp ();
30
31 our $VERSION = '1.0';
32
33 our $C;
34 BEGIN {
35 *C = \$AnyEvent::Watchdog::C;
36 }
37
38 our $AUTORESTART;
39 our $HEARTBEAT_W;
40
41 =item AnyEvent::Watchdog::Util::enabled
42
43 Return true when the program is running under the regime of
44 AnyEvent::Watchdog, false otherwise.
45
46 AnyEvent::Watchdog::Util::enabled
47 or die "watchdog not enabled...";
48 AnyEvent::Watchdog::Util::restart;
49
50 Note that if it returns defined, but false, then AnyEvent::Watchdog is
51 running, but you are in the watchdog process - you probably did something
52 very wrong in this case.
53
54 =cut
55
56 sub enabled() {
57 $AnyEvent::Watchdog::ENABLED
58 }
59
60 =item AnyEvent::Watchdog::restart [$timeout]
61
62 Tells the supervisor to restart the process when it exits, or forcefully
63 after C<$timeout> seconds (minimum 1, maximum 255, default 60).
64
65 Calls C<exit 0> to exit the process cleanly.
66
67 =cut
68
69 sub restart(;$) {
70 my ($timeout) = @_;
71
72 $timeout = 60 unless defined $timeout;
73 $timeout = 1 if $timeout < 1;
74 $timeout = 255 if $timeout > 255;
75
76 syswrite $C, "\x01\x02" . chr $timeout;
77 exit 0;
78 }
79
80 =item AnyEvent::Watchdog::Util::autorestart [$boolean]
81
82 =item use AnyEvent::Watchdog autorestart => $boolean
83
84 Enables or disables autorestart (initially disabled, default for
85 C<$boolean> is to enable): By default, the supervisor will exit if the
86 program exits or dies in any way. When enabling autorestart behaviour,
87 then the supervisor will try to restart the program after it dies.
88
89 Note that the supervisor will never autorestart when the child died with
90 SIGINT or SIGTERM.
91
92 =cut
93
94 sub autorestart(;$) {
95 my $AUTORESTART = !@_ || $_[0];
96
97 unless (enabled) {
98 warn "AnyEvent::Watchdog: watchdog not running, cannot enable autorestart, ignoring.\n"
99 if $AUTORESTART;
100
101 $AUTORESTART = 0;
102
103 return;
104 }
105
106 syswrite $C, $AUTORESTART ? "\x01" : "\x00";
107 }
108
109 =item AnyEvent::Watchdog::heartbeat [$interval]
110
111 =item use AnyEvent::Watchdog heartbeat => $interval
112
113 Tells the supervisor to automatically kill the program if it doesn't
114 react for C<$interval> seconds (minium 1, maximum 255, default 60) , then
115 installs an AnyEvent timer the sends a regular heartbeat to the supervisor
116 twice as often.
117
118 Exit behaviour isn't changed, so if you want a restart instead of an exit,
119 you have to call C<autorestart>.
120
121 The heartbeat frequency can be changed as often as you want, an interval
122 of C<0> disables the heartbeat check again.
123
124 =cut
125
126 sub heartbeat(;$) {
127 my ($interval) = @_;
128
129 unless (enabled) {
130 warn "AnyEvent::Watchdog: watchdog not running, cannot enable heartbeat, ignoring.\n";
131 return;
132 }
133
134 $interval = 60 unless defined $interval;
135 $interval = 1 if $interval < 1;
136 $interval = 255 if $interval > 255;
137
138 syswrite $C, "\x03" . chr $interval;
139
140 $HEARTBEAT_W = AE::timer (0, $interval * 0.5, sub {
141 syswrite $C, "\x04";
142 });
143 }
144
145 =item AnyEvent::Watchdog::on_exit { BLOCK; shift->() }
146
147 Installs an exit hook that is executed when the program is about to exit,
148 while event processing is still active to some extent.
149
150 The hook should do whatever it needs to do (close active connections,
151 disable listeners, write state, free resources etc.). When it is done, it
152 should call the code reference that has been passed to it.
153
154 This means you can install event handlers and return from the block, and
155 the program will not exit until the callback is invoked.
156
157 Exiting "the right way" is surprisingly difficult. This is what C<on_exit>
158 does:
159
160 It installs watchers for C<SIGTERM>, C<SIGINT>, C<SIGXCPU> and C<SIGXFSZ>,
161 and well as an C<END> block (the END block is actually registered
162 in L<AnyEvent::Watchdog>, if possible, so it executes as late as
163 possible). The signal handlers remember the signal and then call C<exit>,
164 invoking the C<END> callback.
165
166 The END block then checks for an exit code of C<255>, in which case
167 nothing happens (C<255> is the exit code that results from a program
168 error), otherwise it runs all C<on_exit> hooks and waits for their
169 completion using the event loop.
170
171 After all C<on_exit> hooks have finished, the program will either be
172 C<exit>ed with the relevant status code (if C<exit> was the cause for the
173 program exit), or it will reset the signal handler, unblock the signal and
174 kill itself with the signal, to ensure that the exit status is correct.
175
176 If the program is running under the watchdog, and autorestart is enabled,
177 then the heartbeat is disabled and the watchdog is told that the program
178 wishes to exit within C<60> seconds, after which it will be forcefully
179 killed.
180
181 All of this should ensure that C<on_exit> hooks are only executed when the
182 program is in a sane state and data structures are still intact. This only
183 works when the program does not install it's own TERM (etc.) watchers, of
184 course, as there is no control over them.
185
186 There is currently no way to unregister C<on_exit> hooks.
187
188 =cut
189
190 our @ON_EXIT;
191 our %SIG_W;
192 our $EXIT_STATUS; # >= 0 exit status; arrayref => signal, undef if exit was just called
193
194 # in case AnyEvent::Watchdog is not loaded, use our own END block
195 END { $AnyEvent::Watchdog::end && &$AnyEvent::Watchdog::end }
196
197 sub _exit {
198 $EXIT_STATUS = $? unless defined $EXIT_STATUS;
199
200 undef $AnyEvent::Watchdog::end;
201
202 my $cv = AE::cv;
203 my $cb = sub { $cv->end };
204
205 $cv->begin;
206 while (@ON_EXIT) {
207 $cv->begin;
208 (pop @ON_EXIT)->($cb);
209 }
210 $cv->end;
211 $cv->recv;
212
213 if (ref $EXIT_STATUS) {
214 # signal
215 # reset to default, hopefully this overrides any C-level handlers
216 $SIG{$EXIT_STATUS->[0]} = 'DEFAULT';
217 eval {
218 # try to unblock
219 require POSIX;
220
221 my $set = POSIX::SigSet->new;
222 $set->addset ($EXIT_STATUS->[1]);
223 POSIX::sigprocmask (POSIX::SIG_UNBLOCK (), $set);
224 };
225 # now raise the signal
226 kill $EXIT_STATUS->[1], $$;
227
228 # well, if we can't force it even now, try exit 255
229 $? = 255;
230 } else {
231 # exit status
232 $? = $EXIT_STATUS;
233 }
234
235 }
236
237 sub on_exit(&) {
238 unless ($AnyEvent::Watchdog::end) {
239 $AnyEvent::Watchdog::end = \&_exit;
240
241 push @ON_EXIT, $_[0];
242
243 for my $signal (qw(TERM INT XFSZ XCPU)) {
244 my $signum = AnyEvent::Base::sig2num $signal
245 or next;
246 $SIG_W{$signum} = AE::signal $signal => sub {
247 $EXIT_STATUS = [$signal => $signum];
248 exit 124;
249 };
250 }
251 }
252 }
253
254 =back
255
256 =head1 SEE ALSO
257
258 L<AnyEvent>.
259
260 =head1 AUTHOR
261
262 Marc Lehmann <schmorp@schmorp.de>
263 http://home.schmorp.de/
264
265 =cut
266
267 1
268