keep namespaces clean
[gitmo/MooseX-Daemonize.git] / lib / MooseX / Daemonize.pm
CommitLineData
5231273c 1use strict;
2use warnings;
a4952679 3package MooseX::Daemonize;
5231273c 4
a4952679 5use Moose::Role;
8ac4733f 6use MooseX::Types::Path::Class;
e803cff5 7use File::Path qw(make_path);
d5a304d9 8use namespace::autoclean;
a392fa53 9
4327fe98 10with 'MooseX::Daemonize::WithPidFile',
11 'MooseX::Getopt';
1d85c76d 12
df3c463b 13sub OK () { 0 }
14sub ERROR () { 1 }
a4952679 15
16has progname => (
5b9ebe08 17 metaclass => 'Getopt',
4327fe98 18 isa => 'Str',
19 is => 'ro',
20 lazy => 1,
21 required => 1,
22 default => sub {
a392fa53 23 ( my $name = lc $_[0]->meta->name ) =~ s/::/_/g;
24 return $name;
25 },
399854a3 26 documentation => 'the name of the daemon',
a4952679 27);
28
d9e417f4 29has pidbase => (
5b9ebe08 30 metaclass => 'Getopt',
4327fe98 31 isa => 'Path::Class::Dir',
32 is => 'ro',
33 coerce => 1,
5b9ebe08 34 required => 1,
4327fe98 35 lazy => 1,
b38ab84f 36 default => sub { Path::Class::Dir->new('', 'var', 'run') },
399854a3 37 documentation => 'the base for our pid (default: /var/run)',
24a6a660 38);
39
d9e417f4 40has basedir => (
5b9ebe08 41 metaclass => 'Getopt',
4327fe98 42 isa => 'Path::Class::Dir',
43 is => 'ro',
44 coerce => 1,
45 required => 1,
46 lazy => 1,
47 default => sub { Path::Class::Dir->new('/') },
399854a3 48 documentation => 'the directory to chdir to (default: /)',
a4952679 49);
50
51has foreground => (
2eced271 52 metaclass => 'Getopt',
cbff8e52 53 cmd_aliases => 'f',
a4952679 54 isa => 'Bool',
55 is => 'ro',
56 default => sub { 0 },
399854a3 57 documentation => 'if true, the process won\'t background',
a4952679 58);
59
b916501e 60has stop_timeout => (
5b9ebe08 61 metaclass => 'Getopt',
4327fe98 62 isa => 'Int',
63 is => 'rw',
399854a3 64 default => sub { 2 },
65 documentation => 'number of seconds to wait for the process to stop, before trying harder to kill it (default: 2 s)',
b916501e 66);
67
5b9ebe08 68# internal book-keeping
69
70has status_message => (
71 metaclass => 'NoGetopt',
72 isa => 'Str',
73 is => 'rw',
74 clearer => 'clear_status_message',
75);
76
77has exit_code => (
78 metaclass => 'NoGetopt',
79 isa => 'Int',
80 is => 'rw',
81 clearer => 'clear_exit_code',
82);
83
4327fe98 84# methods ...
85
86## PID file related stuff ...
87
d9e417f4 88sub init_pidfile {
89 my $self = shift;
90 my $file = $self->pidbase . '/' . $self->progname . '.pid';
e803cff5 91
92 if ( !-d $self->pidbase ) {
93 make_path( $self->pidbase, { error => \my $err } );
94 if (@$err) {
95 confess sprintf( "Cannot create pidbase directory '%s': %s",
96 $self->pidbase, @$err );
97 }
98 }
99
d9e417f4 100 confess "Cannot write to $file" unless (-e $file ? -w $file : -w $self->pidbase);
d8985b7d 101 MooseX::Daemonize::Pid::File->new( file => $file );
d9e417f4 102}
103
5b9ebe08 104# backwards compat,
4327fe98 105sub check { (shift)->pidfile->is_running }
106sub save_pid { (shift)->pidfile->write }
107sub remove_pid { (shift)->pidfile->remove }
108sub get_pid { (shift)->pidfile->pid }
109
110## signal handling ...
111
112sub setup_signals {
113 my $self = shift;
4a24225a 114 $SIG{'INT'} = sub { $self->shutdown };
115# I can't think of a sane default here really ...
116# $SIG{'HUP'} = sub { $self->handle_sighup };
4327fe98 117}
118
4a24225a 119sub shutdown {
120 my $self = shift;
121 $self->pidfile->remove if $self->pidfile->pid == $$;
122 exit(0);
123}
4327fe98 124
125## daemon control methods ...
126
a4952679 127sub start {
5b9ebe08 128 my $self = shift;
129
130 $self->clear_status_message;
131 $self->clear_exit_code;
132
133 if ($self->pidfile->is_running) {
9c8a33b3 134 $self->exit_code($self->OK);
1d85c76d 135 $self->status_message('Daemon is already running with pid (' . $self->pidfile->pid . ')');
5b9ebe08 136 return !($self->exit_code);
137 }
1d85c76d 138
139 if ($self->foreground) {
5b9ebe08 140 $self->is_daemon(1);
141 }
1d85c76d 142 else {
143 eval { $self->daemonize };
5b9ebe08 144 if ($@) {
9c8a33b3 145 $self->exit_code($self->ERROR);
5b9ebe08 146 $self->status_message('Start failed : ' . $@);
147 return !($self->exit_code);
148 }
149 }
cbff8e52 150
5b9ebe08 151 unless ($self->is_daemon) {
1d85c76d 152 $self->exit_code($self->OK);
5b9ebe08 153 $self->status_message('Start succeeded');
154 return !($self->exit_code);
155 }
156
157 $self->pidfile->pid($$);
cbff8e52 158
24a6a660 159 # Change to basedir
160 chdir $self->basedir;
fa2b72a4 161
ff5cee29 162 $self->pidfile->write;
3543c999 163 $self->setup_signals;
164 return $$;
165}
166
5b9ebe08 167sub status {
168 my $self = shift;
169
170 $self->clear_status_message;
171 $self->clear_exit_code;
172
173 if ($self->pidfile->is_running) {
1d85c76d 174 $self->exit_code($self->OK);
175 $self->status_message('Daemon is running with pid (' . $self->pidfile->pid . ')');
5b9ebe08 176 }
1d85c76d 177 else {
9c8a33b3 178 $self->exit_code($self->ERROR);
5b9ebe08 179 $self->status_message('Daemon is not running with pid (' . $self->pidfile->pid . ')');
180 }
181
182 return !($self->exit_code);
183}
184
4327fe98 185sub restart {
5b9ebe08 186 my $self = shift;
187
188 $self->clear_status_message;
189 $self->clear_exit_code;
190
191 unless ($self->stop) {
9c8a33b3 192 $self->exit_code($self->ERROR);
5b9ebe08 193 $self->status_message('Restart (Stop) failed : ' . $@);
194 }
195
196 unless ($self->start) {
9c8a33b3 197 $self->exit_code($self->ERROR);
5b9ebe08 198 $self->status_message('Restart (Start) failed : ' . $@);
199 }
200
9c8a33b3 201 if ($self->exit_code == $self->OK) {
202 $self->exit_code($self->OK);
92cf56b7 203 $self->status_message("Restart successful");
204 }
5b9ebe08 205
206 return !($self->exit_code);
4327fe98 207}
208
b916501e 209# Make _kill *really* private
210my $_kill;
211
3543c999 212sub stop {
5b9ebe08 213 my $self = shift;
214
215 $self->clear_status_message;
216 $self->clear_exit_code;
217
218 # if the pid is not running
b37fcc5f 219 # then we don't need to stop
5b9ebe08 220 # anything ...
221 if ($self->pidfile->is_running) {
222
223 # if we are foreground, then
224 # no need to try and kill
225 # ourselves
226 unless ($self->foreground) {
227
228 # kill the process ...
229 eval { $self->$_kill($self->pidfile->pid) };
230 # and complain if we can't ...
231 if ($@) {
9c8a33b3 232 $self->exit_code($self->ERROR);
5b9ebe08 233 $self->status_message('Stop failed : ' . $@);
234 }
235 # or gloat if we succeed ..
236 else {
9c8a33b3 237 $self->exit_code($self->OK);
5b9ebe08 238 $self->status_message('Stop succeeded');
239 }
240
241 }
5b9ebe08 242 }
243 else {
244 # this just returns the OK
245 # exit code for now, but
246 # we should make this overridable
1d85c76d 247 $self->exit_code($self->OK);
5b9ebe08 248 $self->status_message("Not running");
249 }
250
251 # if we are returning to our script
252 # then we actually need the opposite
253 # of what the system/OS expects
254 return !($self->exit_code);
3543c999 255}
256
b916501e 257$_kill = sub {
a4952679 258 my ( $self, $pid ) = @_;
2361a590 259 return unless $pid;
3543c999 260 unless ( CORE::kill 0 => $pid ) {
3543c999 261 # warn "$pid already appears dead.";
262 return;
263 }
264
265 if ( $pid eq $$ ) {
4a24225a 266 die "$pid is us! Can't commit suicide.";
a4952679 267 }
268
b916501e 269 my $timeout = $self->stop_timeout;
a4952679 270
b916501e 271 # kill 0 => $pid returns 0 if the process is dead
272 # $!{EPERM} could also be true if we cant kill it (permission error)
a4952679 273
b916501e 274 # Try SIGINT ... 2s ... SIGTERM ... 2s ... SIGKILL ... 3s ... UNDEAD!
b6b69aca 275 my $terminating_signal;
b916501e 276 for ( [ 2, $timeout ], [15, $timeout], [9, $timeout * 1.5] ) {
ea9485d8 277 my ($signal, $timeout) = @$_;
278 $timeout = int $timeout;
5b9ebe08 279
ea9485d8 280 CORE::kill($signal, $pid);
5b9ebe08 281
ea9485d8 282 while ($timeout) {
b6b69aca 283 unless(CORE::kill 0 => $pid or $!{EPERM}) {
284 $terminating_signal = $signal;
285 last;
286 }
ea9485d8 287 $timeout--;
b6b69aca 288 sleep(1) if $timeout;
ea9485d8 289 }
b6b69aca 290
291 last if $terminating_signal;
a4952679 292 }
293
b6b69aca 294 if($terminating_signal) {
295 if($terminating_signal == 9) {
296 # clean up the pidfile ourselves iff we used -9 and it worked
297 warn "Had to resort to 'kill -9' and it worked, wiping pidfile";
298 eval { $self->pidfile->remove };
299 if ($@) {
300 warn "Could not remove pidfile ("
301 . $self->pidfile->file
302 . ") because : $!";
303 }
304 }
305 return;
306 }
b916501e 307
308 # IF it is still running
d9e417f4 309 Carp::carp "$pid doesn't seem to want to die."; # AHH EVIL DEAD!
b916501e 310};
a4952679 311
3121;
313__END__
314
8ac4733f 315=pod
316
a4952679 317=head1 NAME
318
892a51e6 319MooseX::Daemonize - Role for daemonizing your Moose based application
a4952679 320
1c60dcf3 321=head1 WARNING
322
323The maintainers of this module now recommend using L<Daemon::Control> instead.
324
a4952679 325=head1 SYNOPSIS
326
4327fe98 327 package My::Daemon;
a4952679 328 use Moose;
5b9ebe08 329
a4952679 330 with qw(MooseX::Daemonize);
5b9ebe08 331
4327fe98 332 # ... define your class ....
5b9ebe08 333
334 after start => sub {
4327fe98 335 my $self = shift;
336 return unless $self->is_daemon;
337 # your daemon code here ...
338 };
a4952679 339
5b9ebe08 340 # then in your script ...
341
4327fe98 342 my $daemon = My::Daemon->new_with_options();
5b9ebe08 343
4327fe98 344 my ($command) = @{$daemon->extra_argv}
345 defined $command || die "No command specified";
5b9ebe08 346
347 $daemon->start if $command eq 'start';
348 $daemon->status if $command eq 'status';
349 $daemon->restart if $command eq 'restart';
350 $daemon->stop if $command eq 'stop';
351
92cf56b7 352 warn($daemon->status_message);
5b9ebe08 353 exit($daemon->exit_code);
354
a4952679 355=head1 DESCRIPTION
356
b37fcc5f 357Often you want to write a persistent daemon that has a pid file, and responds
5b9ebe08 358appropriately to Signals. This module provides a set of basic roles as an
4327fe98 359infrastructure to do that.
a4952679 360
05b96f4d 361=head1 CAVEATS
362
363When going into background MooseX::Daemonize closes all open file
364handles. This may interfere with you logging because it may also close the log
365file handle you want to write to. To prevent this you can either defer opening
366the log file until after start. Alternatively, use can use the
367'dont_close_all_files' option either from the command line or in your .sh
368script.
369
370Assuming you want to use Log::Log4perl for example you could expand the
371MooseX::Daemonize example above like this.
372
373 after start => sub {
374 my $self = shift;
375 return unless $self->is_daemon;
376 Log::Log4perl->init(\$log4perl_config);
377 my $logger = Log::Log4perl->get_logger();
378 $logger->info("Daemon started");
379 # your daemon code here ...
380 };
381
382
a4952679 383=head1 ATTRIBUTES
384
4327fe98 385This list includes attributes brought in from other roles as well
386we include them here for ease of documentation. All of these attributes
5b9ebe08 387are settable though L<MooseX::Getopt>'s command line handling, with the
4327fe98 388exception of C<is_daemon>.
389
a4952679 390=over
391
4327fe98 392=item I<progname Path::Class::Dir | Str>
a4952679 393
4327fe98 394The name of our daemon, defaults to C<$package_name =~ s/::/_/>;
a4952679 395
4327fe98 396=item I<pidbase Path::Class::Dir | Str>
a4952679 397
1d85c76d 398The base for our PID, defaults to C</var/run/>
a4952679 399
f453ca7b 400=item I<basedir Path::Class::Dir | Str>
401
402The directory we chdir to; defaults to C</>.
403
4327fe98 404=item I<pidfile MooseX::Daemonize::Pid::File | Str>
a4952679 405
1d85c76d 406The file we store our PID in, defaults to C<$pidbase/$progname.pid>
a4952679 407
4327fe98 408=item I<foreground Bool>
a4952679 409
5b9ebe08 410If true, the process won't background. Useful for debugging. This option can
b916501e 411be set via Getopt's -f.
a4952679 412
2ecc2ccb 413=item I<no_double_fork Bool>
414
415If true, the process will not perform the typical double-fork, which is extra
b37fcc5f 416added protection from your process accidentally acquiring a controlling terminal.
2ecc2ccb 417More information can be found by Googling "double fork daemonize".
418
419=item I<ignore_zombies Bool>
420
421If true, the process will not clean up zombie processes.
422Normally you don't want this.
423
424=item I<dont_close_all_files Bool>
425
426If true, the objects open filehandles will not be closed when daemonized.
427Normally you don't want this.
428
429
4327fe98 430=item I<is_daemon Bool>
431
5b9ebe08 432If true, the process is the backgrounded daemon process, if false it is the
433parent process. This is useful for example in an C<after 'start' => sub { }>
434block.
e7a196e7 435
4327fe98 436B<NOTE:> This option is explicitly B<not> available through L<MooseX::Getopt>.
b916501e 437
4327fe98 438=item I<stop_timeout>
b916501e 439
440Number of seconds to wait for the process to stop, before trying harder to kill
4327fe98 441it. Defaults to 2 seconds.
e7a196e7 442
a4952679 443=back
444
5b9ebe08 445These are the internal attributes, which are not available through MooseX::Getopt.
446
447=over 4
448
449=item I<exit_code Int>
450
92cf56b7 451=item I<status_message Str>
5b9ebe08 452
453=back
454
455=head1 METHODS
a4952679 456
4327fe98 457=head2 Daemon Control Methods
458
5b9ebe08 459These methods can be used to control the daemon behavior. Every effort
460has been made to have these methods DWIM (Do What I Mean), so that you
461can focus on just writing the code for your daemon.
a4952679 462
5b9ebe08 463Extending these methods is best done with the L<Moose> method modifiers,
4327fe98 464such as C<before>, C<after> and C<around>.
465
466=over 4
467
468=item B<start>
a4952679 469
470Setup a pidfile, fork, then setup the signal handlers.
471
4327fe98 472=item B<stop>
a4952679 473
474Stop the process matching the pidfile, and unlinks the pidfile.
475
4327fe98 476=item B<restart>
a4952679 477
4327fe98 478Literally this is:
a4952679 479
480 $self->stop();
481 $self->start();
482
5b9ebe08 483=item B<status>
484
92cf56b7 485=item B<shutdown>
486
4327fe98 487=back
488
5b9ebe08 489
4327fe98 490=head2 Pidfile Handling Methods
491
492=over 4
493
494=item B<init_pidfile>
495
496This method will create a L<MooseX::Daemonize::Pid::File> object and tell
497it to store the PID in the file C<$pidbase/$progname.pid>.
498
499=item B<check>
500
5b9ebe08 501This checks to see if the daemon process is currently running by checking
4327fe98 502the pidfile.
a4952679 503
4327fe98 504=item B<get_pid>
a4952679 505
4327fe98 506Returns the PID of the daemon process.
a4952679 507
4327fe98 508=item B<save_pid>
a4952679 509
4327fe98 510Write the pidfile.
511
512=item B<remove_pid>
513
514Removes the pidfile.
515
516=back
517
518=head2 Signal Handling Methods
519
520=over 4
521
522=item B<setup_signals>
523
5b9ebe08 524Setup the signal handlers, by default it only sets up handlers for SIGINT and
4327fe98 525SIGHUP. If you wish to add more signals just use the C<after> method modifier
526and add them.
527
528=item B<handle_sigint>
a4952679 529
cecbee2d 530Handle a INT signal, by default calls C<$self->stop()>
a4952679 531
4327fe98 532=item B<handle_sighup>
a4952679 533
cecbee2d 534Handle a HUP signal. By default calls C<$self->restart()>
a4952679 535
4327fe98 536=back
537
9c8a33b3 538=head2 Exit Code Methods
539
b37fcc5f 540These are overridable constant methods used for setting the exit code.
9c8a33b3 541
542=over 4
543
544=item OK
545
546Returns 0.
547
548=item ERROR
549
550Returns 1.
551
552=back
553
4327fe98 554=head2 Introspection
555
556=over 4
557
a4952679 558=item meta()
559
cecbee2d 560The C<meta()> method from L<Class::MOP::Class>
a4952679 561
562=back
563
564=head1 DEPENDENCIES
565
4327fe98 566L<Moose>, L<MooseX::Getopt>, L<MooseX::Types::Path::Class> and L<POSIX>
a4952679 567
568=head1 INCOMPATIBILITIES
569
4327fe98 570None reported. Although obviously this will not work on Windows.
a4952679 571
572=head1 BUGS AND LIMITATIONS
573
a4952679 574No bugs have been reported.
575
576Please report any bugs or feature requests to
568a7a76 577C<bug-MooseX-Daemonize@rt.cpan.org>, or through the web interface at
a4952679 578L<http://rt.cpan.org>.
579
580=head1 SEE ALSO
581
92b4ca7e 582L<Daemon::Control>, L<Proc::Daemon>, L<Daemon::Generic>
a4952679 583
92cf56b7 584=head1 AUTHORS
a4952679 585
69186a48 586Chris Prather C<< <chris@prather.org >>
a4952679 587
92cf56b7 588Stevan Little C<< <stevan.little@iinteractive.com> >>
589
7ada91b8 590=head1 THANKS
591
5b9ebe08 592Mike Boyko, Matt S. Trout, Stevan Little, Brandon Black, Ash Berlin and the
b916501e 593#moose denzians
a4952679 594
637573c4 595Some bug fixes sponsored by Takkle Inc.
596
a4952679 597=head1 LICENCE AND COPYRIGHT
598
05b96f4d 599Copyright (c) 2007-2011, Chris Prather C<< <chris@prather.org> >>. Some rights
b916501e 600reserved.
a4952679 601
602This module is free software; you can redistribute it and/or
603modify it under the same terms as Perl itself. See L<perlartistic>.
604
a4952679 605=head1 DISCLAIMER OF WARRANTY
606
607BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
608FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
609OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
610PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
611EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
612WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
613ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
614YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
615NECESSARY SERVICING, REPAIR, OR CORRECTION.
616
617IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
618WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
619REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
620LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
621OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
622THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
623RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
624FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
625SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
626SUCH DAMAGES.
8ac4733f 627
628=cut