1 package MooseX::Daemonize;
2 use strict; # because Kwalitee is pedantic
4 use MooseX::Types::Path::Class;
8 with 'MooseX::Daemonize::WithPidFile',
12 metaclass => 'Getopt',
18 ( my $name = lc $_[0]->meta->name ) =~ s/::/_/g;
24 metaclass => 'Getopt',
25 isa => 'Path::Class::Dir',
30 default => sub { Path::Class::Dir->new('var', 'run') },
34 metaclass => 'Getopt',
35 isa => 'Path::Class::Dir',
40 default => sub { Path::Class::Dir->new('/') },
44 metaclass => 'Getopt',
52 metaclass => 'Getopt',
58 # internal book-keeping
60 has status_message => (
61 metaclass => 'NoGetopt',
64 clearer => 'clear_status_message',
68 metaclass => 'NoGetopt',
71 clearer => 'clear_exit_code',
76 ## PID file related stuff ...
80 my $file = $self->pidbase . '/' . $self->progname . '.pid';
81 confess "Cannot write to $file" unless (-e $file ? -w $file : -w $self->pidbase);
82 MooseX::Daemonize::Pid::File->new( file => $file );
86 sub check { (shift)->pidfile->is_running }
87 sub save_pid { (shift)->pidfile->write }
88 sub remove_pid { (shift)->pidfile->remove }
89 sub get_pid { (shift)->pidfile->pid }
91 ## signal handling ...
95 $SIG{'INT'} = sub { $self->handle_sigint };
96 $SIG{'HUP'} = sub { $self->handle_sighup };
99 sub handle_sigint { $_[0]->stop }
100 sub handle_sighup { $_[0]->restart }
102 ## daemon control methods ...
107 $self->clear_status_message;
108 $self->clear_exit_code;
110 if ($self->pidfile->is_running) {
111 $self->status_message('Daemon is already running with pid (' . $self->pidfile->pid . ')');
112 return !($self->exit_code);
115 if ($self->foreground) {
119 eval { $self->daemonize };
122 $self->status_message('Start failed : ' . $@);
123 return !($self->exit_code);
127 unless ($self->is_daemon) {
128 $self->status_message('Start succeeded');
129 return !($self->exit_code);
132 $self->pidfile->pid($$);
135 chdir $self->basedir;
137 $self->pidfile->write;
138 $self->setup_signals;
145 $self->clear_status_message;
146 $self->clear_exit_code;
148 if ($self->pidfile->is_running) {
149 $self->status_message('Daemon is running with pid (' . $self->pidfile->pid . ')');
153 $self->status_message('Daemon is not running with pid (' . $self->pidfile->pid . ')');
156 return !($self->exit_code);
162 $self->clear_status_message;
163 $self->clear_exit_code;
165 unless ($self->stop) {
167 $self->status_message('Restart (Stop) failed : ' . $@);
170 unless ($self->start) {
172 $self->status_message('Restart (Start) failed : ' . $@);
175 $self->status_message("Restart successful")
176 if !$self->exit_code;
178 return !($self->exit_code);
181 # Make _kill *really* private
187 $self->clear_status_message;
188 $self->clear_exit_code;
190 # if the pid is not running
191 # then we dont need to stop
193 if ($self->pidfile->is_running) {
195 # if we are foreground, then
196 # no need to try and kill
198 unless ($self->foreground) {
200 # kill the process ...
201 eval { $self->$_kill($self->pidfile->pid) };
202 # and complain if we can't ...
205 $self->status_message('Stop failed : ' . $@);
207 # or gloat if we succeed ..
209 $self->status_message('Stop succeeded');
215 eval { $self->pidfile->remove };
217 warn "Could not remove pidfile ("
218 . $self->pidfile->file
224 # this just returns the OK
225 # exit code for now, but
226 # we should make this overridable
227 $self->status_message("Not running");
230 # if we are returning to our script
231 # then we actually need the opposite
232 # of what the system/OS expects
233 return !($self->exit_code);
237 my ( $self, $pid ) = @_;
239 unless ( CORE::kill 0 => $pid ) {
241 # warn "$pid already appears dead.";
247 # warn "$pid is us! Can't commit suicide.";
251 my $timeout = $self->stop_timeout;
253 # kill 0 => $pid returns 0 if the process is dead
254 # $!{EPERM} could also be true if we cant kill it (permission error)
256 # if this is being called
257 # inside the daemon then
258 # we don't want sig-INT to
259 # fall into a loop here
261 if ($self->is_daemon) {
262 $SIG{INT} = 'DEFAULT';
265 # Try SIGINT ... 2s ... SIGTERM ... 2s ... SIGKILL ... 3s ... UNDEAD!
266 for ( [ 2, $timeout ], [15, $timeout], [9, $timeout * 1.5] ) {
267 my ($signal, $timeout) = @$_;
268 $timeout = int $timeout;
270 CORE::kill($signal, $pid);
272 last unless CORE::kill 0 => $pid or $!{EPERM};
276 last unless CORE::kill 0 => $pid or $!{EPERM};
281 return unless ( CORE::kill 0 => $pid or $!{EPERM} );
283 # IF it is still running
284 Carp::carp "$pid doesn't seem to want to die."; # AHH EVIL DEAD!
294 MooseX::Daemonize - provides a Role that daemonizes your Moose based
299 This document describes MooseX::Daemonize version 0.05
306 with qw(MooseX::Daemonize);
308 # ... define your class ....
312 return unless $self->is_daemon;
313 # your daemon code here ...
316 # then in your script ...
318 my $daemon = My::Daemon->new_with_options();
320 my ($command) = @{$daemon->extra_argv}
321 defined $command || die "No command specified";
323 $daemon->start if $command eq 'start';
324 $daemon->status if $command eq 'status';
325 $daemon->restart if $command eq 'restart';
326 $daemon->stop if $command eq 'stop';
328 warn($daemon->status);
329 exit($daemon->exit_code);
333 Often you want to write a persistant daemon that has a pid file, and responds
334 appropriately to Signals. This module provides a set of basic roles as an
335 infrastructure to do that.
339 This list includes attributes brought in from other roles as well
340 we include them here for ease of documentation. All of these attributes
341 are settable though L<MooseX::Getopt>'s command line handling, with the
342 exception of C<is_daemon>.
346 =item I<progname Path::Class::Dir | Str>
348 The name of our daemon, defaults to C<$package_name =~ s/::/_/>;
350 =item I<pidbase Path::Class::Dir | Str>
352 The base for our bid, defaults to C</var/run/$progname>
354 =item I<pidfile MooseX::Daemonize::Pid::File | Str>
356 The file we store our PID in, defaults to C</var/run/$progname>
358 =item I<foreground Bool>
360 If true, the process won't background. Useful for debugging. This option can
361 be set via Getopt's -f.
363 =item I<is_daemon Bool>
365 If true, the process is the backgrounded daemon process, if false it is the
366 parent process. This is useful for example in an C<after 'start' => sub { }>
369 B<NOTE:> This option is explicitly B<not> available through L<MooseX::Getopt>.
371 =item I<stop_timeout>
373 Number of seconds to wait for the process to stop, before trying harder to kill
374 it. Defaults to 2 seconds.
378 These are the internal attributes, which are not available through MooseX::Getopt.
382 =item I<exit_code Int>
390 =head2 Daemon Control Methods
392 These methods can be used to control the daemon behavior. Every effort
393 has been made to have these methods DWIM (Do What I Mean), so that you
394 can focus on just writing the code for your daemon.
396 Extending these methods is best done with the L<Moose> method modifiers,
397 such as C<before>, C<after> and C<around>.
403 Setup a pidfile, fork, then setup the signal handlers.
407 Stop the process matching the pidfile, and unlinks the pidfile.
421 =head2 Pidfile Handling Methods
425 =item B<init_pidfile>
427 This method will create a L<MooseX::Daemonize::Pid::File> object and tell
428 it to store the PID in the file C<$pidbase/$progname.pid>.
432 This checks to see if the daemon process is currently running by checking
437 Returns the PID of the daemon process.
449 =head2 Signal Handling Methods
453 =item B<setup_signals>
455 Setup the signal handlers, by default it only sets up handlers for SIGINT and
456 SIGHUP. If you wish to add more signals just use the C<after> method modifier
459 =item B<handle_sigint>
461 Handle a INT signal, by default calls C<$self->stop()>
463 =item B<handle_sighup>
465 Handle a HUP signal. By default calls C<$self->restart()>
475 The C<meta()> method from L<Class::MOP::Class>
481 L<Moose>, L<MooseX::Getopt>, L<MooseX::Types::Path::Class> and L<POSIX>
483 =head1 INCOMPATIBILITIES
485 None reported. Although obviously this will not work on Windows.
487 =head1 BUGS AND LIMITATIONS
489 No bugs have been reported.
491 Please report any bugs or feature requests to
492 C<bug-acme-dahut-call@rt.cpan.org>, or through the web interface at
493 L<http://rt.cpan.org>.
497 L<Proc::Daemon>, L<Daemon::Generic>
501 Chris Prather C<< <perigrin@cpan.org> >>
505 Mike Boyko, Matt S. Trout, Stevan Little, Brandon Black, Ash Berlin and the
508 Some bug fixes sponsored by Takkle Inc.
510 =head1 LICENCE AND COPYRIGHT
512 Copyright (c) 2007, Chris Prather C<< <perigrin@cpan.org> >>. All rights
515 This module is free software; you can redistribute it and/or
516 modify it under the same terms as Perl itself. See L<perlartistic>.
518 =head1 DISCLAIMER OF WARRANTY
520 BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
521 FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
522 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
523 PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
524 EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
525 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
526 ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
527 YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
528 NECESSARY SERVICING, REPAIR, OR CORRECTION.
530 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
531 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
532 REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
533 LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
534 OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
535 THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
536 RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
537 FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
538 SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF