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->shutdown };
96 # I can't think of a sane default here really ...
97 # $SIG{'HUP'} = sub { $self->handle_sighup };
102 $self->pidfile->remove if $self->pidfile->pid == $$;
106 ## daemon control methods ...
111 $self->clear_status_message;
112 $self->clear_exit_code;
114 if ($self->pidfile->is_running) {
115 $self->status_message('Daemon is already running with pid (' . $self->pidfile->pid . ')');
116 return !($self->exit_code);
119 if ($self->foreground) {
123 eval { $self->daemonize };
126 $self->status_message('Start failed : ' . $@);
127 return !($self->exit_code);
131 unless ($self->is_daemon) {
132 $self->status_message('Start succeeded');
133 return !($self->exit_code);
136 $self->pidfile->pid($$);
139 chdir $self->basedir;
141 $self->pidfile->write;
142 $self->setup_signals;
149 $self->clear_status_message;
150 $self->clear_exit_code;
152 if ($self->pidfile->is_running) {
153 $self->status_message('Daemon is running with pid (' . $self->pidfile->pid . ')');
157 $self->status_message('Daemon is not running with pid (' . $self->pidfile->pid . ')');
160 return !($self->exit_code);
166 $self->clear_status_message;
167 $self->clear_exit_code;
169 unless ($self->stop) {
171 $self->status_message('Restart (Stop) failed : ' . $@);
174 unless ($self->start) {
176 $self->status_message('Restart (Start) failed : ' . $@);
179 $self->status_message("Restart successful")
180 if !$self->exit_code;
182 return !($self->exit_code);
185 # Make _kill *really* private
191 $self->clear_status_message;
192 $self->clear_exit_code;
194 # if the pid is not running
195 # then we dont need to stop
197 if ($self->pidfile->is_running) {
199 # if we are foreground, then
200 # no need to try and kill
202 unless ($self->foreground) {
204 # kill the process ...
205 eval { $self->$_kill($self->pidfile->pid) };
206 # and complain if we can't ...
209 $self->status_message('Stop failed : ' . $@);
211 # or gloat if we succeed ..
213 $self->status_message('Stop succeeded');
219 eval { $self->pidfile->remove };
221 warn "Could not remove pidfile ("
222 . $self->pidfile->file
228 # this just returns the OK
229 # exit code for now, but
230 # we should make this overridable
231 $self->status_message("Not running");
234 # if we are returning to our script
235 # then we actually need the opposite
236 # of what the system/OS expects
237 return !($self->exit_code);
241 my ( $self, $pid ) = @_;
243 unless ( CORE::kill 0 => $pid ) {
244 # warn "$pid already appears dead.";
249 die "$pid is us! Can't commit suicide.";
252 my $timeout = $self->stop_timeout;
254 # kill 0 => $pid returns 0 if the process is dead
255 # $!{EPERM} could also be true if we cant kill it (permission error)
257 # Try SIGINT ... 2s ... SIGTERM ... 2s ... SIGKILL ... 3s ... UNDEAD!
258 for ( [ 2, $timeout ], [15, $timeout], [9, $timeout * 1.5] ) {
259 my ($signal, $timeout) = @$_;
260 $timeout = int $timeout;
262 CORE::kill($signal, $pid);
264 last unless CORE::kill 0 => $pid or $!{EPERM};
268 last unless CORE::kill 0 => $pid or $!{EPERM};
273 return unless ( CORE::kill 0 => $pid or $!{EPERM} );
275 # IF it is still running
276 Carp::carp "$pid doesn't seem to want to die."; # AHH EVIL DEAD!
286 MooseX::Daemonize - provides a Role that daemonizes your Moose based
291 This document describes MooseX::Daemonize version 0.05
298 with qw(MooseX::Daemonize);
300 # ... define your class ....
304 return unless $self->is_daemon;
305 # your daemon code here ...
308 # then in your script ...
310 my $daemon = My::Daemon->new_with_options();
312 my ($command) = @{$daemon->extra_argv}
313 defined $command || die "No command specified";
315 $daemon->start if $command eq 'start';
316 $daemon->status if $command eq 'status';
317 $daemon->restart if $command eq 'restart';
318 $daemon->stop if $command eq 'stop';
320 warn($daemon->status);
321 exit($daemon->exit_code);
325 Often you want to write a persistant daemon that has a pid file, and responds
326 appropriately to Signals. This module provides a set of basic roles as an
327 infrastructure to do that.
331 This list includes attributes brought in from other roles as well
332 we include them here for ease of documentation. All of these attributes
333 are settable though L<MooseX::Getopt>'s command line handling, with the
334 exception of C<is_daemon>.
338 =item I<progname Path::Class::Dir | Str>
340 The name of our daemon, defaults to C<$package_name =~ s/::/_/>;
342 =item I<pidbase Path::Class::Dir | Str>
344 The base for our bid, defaults to C</var/run/$progname>
346 =item I<pidfile MooseX::Daemonize::Pid::File | Str>
348 The file we store our PID in, defaults to C</var/run/$progname>
350 =item I<foreground Bool>
352 If true, the process won't background. Useful for debugging. This option can
353 be set via Getopt's -f.
355 =item I<is_daemon Bool>
357 If true, the process is the backgrounded daemon process, if false it is the
358 parent process. This is useful for example in an C<after 'start' => sub { }>
361 B<NOTE:> This option is explicitly B<not> available through L<MooseX::Getopt>.
363 =item I<stop_timeout>
365 Number of seconds to wait for the process to stop, before trying harder to kill
366 it. Defaults to 2 seconds.
370 These are the internal attributes, which are not available through MooseX::Getopt.
374 =item I<exit_code Int>
382 =head2 Daemon Control Methods
384 These methods can be used to control the daemon behavior. Every effort
385 has been made to have these methods DWIM (Do What I Mean), so that you
386 can focus on just writing the code for your daemon.
388 Extending these methods is best done with the L<Moose> method modifiers,
389 such as C<before>, C<after> and C<around>.
395 Setup a pidfile, fork, then setup the signal handlers.
399 Stop the process matching the pidfile, and unlinks the pidfile.
413 =head2 Pidfile Handling Methods
417 =item B<init_pidfile>
419 This method will create a L<MooseX::Daemonize::Pid::File> object and tell
420 it to store the PID in the file C<$pidbase/$progname.pid>.
424 This checks to see if the daemon process is currently running by checking
429 Returns the PID of the daemon process.
441 =head2 Signal Handling Methods
445 =item B<setup_signals>
447 Setup the signal handlers, by default it only sets up handlers for SIGINT and
448 SIGHUP. If you wish to add more signals just use the C<after> method modifier
451 =item B<handle_sigint>
453 Handle a INT signal, by default calls C<$self->stop()>
455 =item B<handle_sighup>
457 Handle a HUP signal. By default calls C<$self->restart()>
467 The C<meta()> method from L<Class::MOP::Class>
473 L<Moose>, L<MooseX::Getopt>, L<MooseX::Types::Path::Class> and L<POSIX>
475 =head1 INCOMPATIBILITIES
477 None reported. Although obviously this will not work on Windows.
479 =head1 BUGS AND LIMITATIONS
481 No bugs have been reported.
483 Please report any bugs or feature requests to
484 C<bug-acme-dahut-call@rt.cpan.org>, or through the web interface at
485 L<http://rt.cpan.org>.
489 L<Proc::Daemon>, L<Daemon::Generic>
493 Chris Prather C<< <perigrin@cpan.org> >>
497 Mike Boyko, Matt S. Trout, Stevan Little, Brandon Black, Ash Berlin and the
500 Some bug fixes sponsored by Takkle Inc.
502 =head1 LICENCE AND COPYRIGHT
504 Copyright (c) 2007, Chris Prather C<< <perigrin@cpan.org> >>. All rights
507 This module is free software; you can redistribute it and/or
508 modify it under the same terms as Perl itself. See L<perlartistic>.
510 =head1 DISCLAIMER OF WARRANTY
512 BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
513 FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
514 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
515 PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
516 EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
517 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
518 ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
519 YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
520 NECESSARY SERVICING, REPAIR, OR CORRECTION.
522 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
523 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
524 REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
525 LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
526 OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
527 THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
528 RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
529 FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
530 SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF