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