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