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