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