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',
60 ## PID file related stuff ...
64 my $file = $self->pidbase . '/' . $self->progname . '.pid';
65 confess "Cannot write to $file" unless (-e $file ? -w $file : -w $self->pidbase);
66 MooseX::Daemonize::Pid::File->new( file => $file );
70 sub check { (shift)->pidfile->is_running }
71 sub save_pid { (shift)->pidfile->write }
72 sub remove_pid { (shift)->pidfile->remove }
73 sub get_pid { (shift)->pidfile->pid }
75 ## signal handling ...
79 $SIG{'INT'} = sub { $self->handle_sigint };
80 $SIG{'HUP'} = sub { $self->handle_sighup };
83 sub handle_sigint { $_[0]->stop; }
84 sub handle_sighup { $_[0]->restart; }
86 ## daemon control methods ...
91 confess "instance already running" if $self->pidfile->is_running;
93 $self->daemonize unless $self->foreground;
95 return unless $self->is_daemon;
97 $self->pidfile->pid($$);
100 chdir $self->basedir;
102 $self->pidfile->write;
103 $self->setup_signals;
109 $self->stop( no_exit => 1 );
113 # Make _kill *really* private
117 my ( $self, %args ) = @_;
118 my $pid = $self->pidfile->pid;
119 $self->$_kill($pid) unless $self->foreground();
120 $self->pidfile->remove;
121 return 1 if $args{no_exit};
126 my ( $self, $pid ) = @_;
128 unless ( CORE::kill 0 => $pid ) {
130 # warn "$pid already appears dead.";
136 # warn "$pid is us! Can't commit suicide.";
140 my $timeout = $self->stop_timeout;
142 # kill 0 => $pid returns 0 if the process is dead
143 # $!{EPERM} could also be true if we cant kill it (permission error)
145 # Try SIGINT ... 2s ... SIGTERM ... 2s ... SIGKILL ... 3s ... UNDEAD!
146 for ( [ 2, $timeout ], [15, $timeout], [9, $timeout * 1.5] ) {
147 my ($signal, $timeout) = @$_;
148 $timeout = int $timeout;
150 CORE::kill($signal, $pid);
152 last unless CORE::kill 0 => $pid or $!{EPERM};
156 last unless CORE::kill 0 => $pid or $!{EPERM};
161 return unless ( CORE::kill 0 => $pid or $!{EPERM} );
163 # IF it is still running
164 Carp::carp "$pid doesn't seem to want to die."; # AHH EVIL DEAD!
174 MooseX::Daemonize - provides a Role that daemonizes your Moose based
179 This document describes MooseX::Daemonize version 0.05
186 with qw(MooseX::Daemonize);
188 # ... define your class ....
192 return unless $self->is_daemon;
193 # your daemon code here ...
196 # then in your script ...
198 my $daemon = My::Daemon->new_with_options();
200 my ($command) = @{$daemon->extra_argv}
201 defined $command || die "No command specified";
203 $daemon->start() if $command eq 'start';
204 $daemon->stop() if $command eq 'stop';
208 Often you want to write a persistant daemon that has a pid file, and responds
209 appropriately to Signals. This module provides a set of basic roles as an
210 infrastructure to do that.
214 This list includes attributes brought in from other roles as well
215 we include them here for ease of documentation. All of these attributes
216 are settable though L<MooseX::Getopt>'s command line handling, with the
217 exception of C<is_daemon>.
221 =item I<progname Path::Class::Dir | Str>
223 The name of our daemon, defaults to C<$package_name =~ s/::/_/>;
225 =item I<pidbase Path::Class::Dir | Str>
227 The base for our bid, defaults to C</var/run/$progname>
229 =item I<pidfile MooseX::Daemonize::Pid::File | Str>
231 The file we store our PID in, defaults to C</var/run/$progname>
233 =item I<foreground Bool>
235 If true, the process won't background. Useful for debugging. This option can
236 be set via Getopt's -f.
238 =item I<is_daemon Bool>
240 If true, the process is the backgrounded daemon process, if false it is the
241 parent process. This is useful for example in an C<after 'start' => sub { }>
244 B<NOTE:> This option is explicitly B<not> available through L<MooseX::Getopt>.
246 =item I<stop_timeout>
248 Number of seconds to wait for the process to stop, before trying harder to kill
249 it. Defaults to 2 seconds.
255 =head2 Daemon Control Methods
257 These methods can be used to control the daemon behavior. Every effort
258 has been made to have these methods DWIM (Do What I Mean), so that you
259 can focus on just writing the code for your daemon.
261 Extending these methods is best done with the L<Moose> method modifiers,
262 such as C<before>, C<after> and C<around>.
268 Setup a pidfile, fork, then setup the signal handlers.
272 Stop the process matching the pidfile, and unlinks the pidfile.
283 =head2 Pidfile Handling Methods
287 =item B<init_pidfile>
289 This method will create a L<MooseX::Daemonize::Pid::File> object and tell
290 it to store the PID in the file C<$pidbase/$progname.pid>.
294 This checks to see if the daemon process is currently running by checking
299 Returns the PID of the daemon process.
311 =head2 Signal Handling Methods
315 =item B<setup_signals>
317 Setup the signal handlers, by default it only sets up handlers for SIGINT and
318 SIGHUP. If you wish to add more signals just use the C<after> method modifier
321 =item B<handle_sigint>
323 Handle a INT signal, by default calls C<$self->stop()>
325 =item B<handle_sighup>
327 Handle a HUP signal. By default calls C<$self->restart()>
337 The C<meta()> method from L<Class::MOP::Class>
343 L<Moose>, L<MooseX::Getopt>, L<MooseX::Types::Path::Class> and L<POSIX>
345 =head1 INCOMPATIBILITIES
347 None reported. Although obviously this will not work on Windows.
349 =head1 BUGS AND LIMITATIONS
351 No bugs have been reported.
353 Please report any bugs or feature requests to
354 C<bug-acme-dahut-call@rt.cpan.org>, or through the web interface at
355 L<http://rt.cpan.org>.
359 L<Proc::Daemon>, L<Daemon::Generic>
363 Chris Prather C<< <perigrin@cpan.org> >>
367 Mike Boyko, Matt S. Trout, Stevan Little, Brandon Black, Ash Berlin and the
370 Some bug fixes sponsored by Takkle Inc.
372 =head1 LICENCE AND COPYRIGHT
374 Copyright (c) 2007, Chris Prather C<< <perigrin@cpan.org> >>. All rights
377 This module is free software; you can redistribute it and/or
378 modify it under the same terms as Perl itself. See L<perlartistic>.
380 =head1 DISCLAIMER OF WARRANTY
382 BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
383 FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
384 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
385 PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
386 EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
387 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
388 ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
389 YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
390 NECESSARY SERVICING, REPAIR, OR CORRECTION.
392 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
393 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
394 REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
395 LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
396 OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
397 THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
398 RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
399 FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
400 SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF