document the basedir attribute (defaults to /) - RT#83055
[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
62b880da 7our $VERSION = '0.15';
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
105dcffa 317This document describes MooseX::Daemonize version 0.15
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
f453ca7b 398=item I<basedir Path::Class::Dir | Str>
399
400The directory we chdir to; defaults to C</>.
401
4327fe98 402=item I<pidfile MooseX::Daemonize::Pid::File | Str>
a4952679 403
1d85c76d 404The file we store our PID in, defaults to C<$pidbase/$progname.pid>
a4952679 405
4327fe98 406=item I<foreground Bool>
a4952679 407
5b9ebe08 408If true, the process won't background. Useful for debugging. This option can
b916501e 409be set via Getopt's -f.
a4952679 410
2ecc2ccb 411=item I<no_double_fork Bool>
412
413If true, the process will not perform the typical double-fork, which is extra
414added protection from your process accidentally aquiring a controlling terminal.
415More information can be found by Googling "double fork daemonize".
416
417=item I<ignore_zombies Bool>
418
419If true, the process will not clean up zombie processes.
420Normally you don't want this.
421
422=item I<dont_close_all_files Bool>
423
424If true, the objects open filehandles will not be closed when daemonized.
425Normally you don't want this.
426
427
4327fe98 428=item I<is_daemon Bool>
429
5b9ebe08 430If true, the process is the backgrounded daemon process, if false it is the
431parent process. This is useful for example in an C<after 'start' => sub { }>
432block.
e7a196e7 433
4327fe98 434B<NOTE:> This option is explicitly B<not> available through L<MooseX::Getopt>.
b916501e 435
4327fe98 436=item I<stop_timeout>
b916501e 437
438Number of seconds to wait for the process to stop, before trying harder to kill
4327fe98 439it. Defaults to 2 seconds.
e7a196e7 440
a4952679 441=back
442
5b9ebe08 443These are the internal attributes, which are not available through MooseX::Getopt.
444
445=over 4
446
447=item I<exit_code Int>
448
92cf56b7 449=item I<status_message Str>
5b9ebe08 450
451=back
452
453=head1 METHODS
a4952679 454
4327fe98 455=head2 Daemon Control Methods
456
5b9ebe08 457These methods can be used to control the daemon behavior. Every effort
458has been made to have these methods DWIM (Do What I Mean), so that you
459can focus on just writing the code for your daemon.
a4952679 460
5b9ebe08 461Extending these methods is best done with the L<Moose> method modifiers,
4327fe98 462such as C<before>, C<after> and C<around>.
463
464=over 4
465
466=item B<start>
a4952679 467
468Setup a pidfile, fork, then setup the signal handlers.
469
4327fe98 470=item B<stop>
a4952679 471
472Stop the process matching the pidfile, and unlinks the pidfile.
473
4327fe98 474=item B<restart>
a4952679 475
4327fe98 476Literally this is:
a4952679 477
478 $self->stop();
479 $self->start();
480
5b9ebe08 481=item B<status>
482
92cf56b7 483=item B<shutdown>
484
4327fe98 485=back
486
5b9ebe08 487
4327fe98 488=head2 Pidfile Handling Methods
489
490=over 4
491
492=item B<init_pidfile>
493
494This method will create a L<MooseX::Daemonize::Pid::File> object and tell
495it to store the PID in the file C<$pidbase/$progname.pid>.
496
497=item B<check>
498
5b9ebe08 499This checks to see if the daemon process is currently running by checking
4327fe98 500the pidfile.
a4952679 501
4327fe98 502=item B<get_pid>
a4952679 503
4327fe98 504Returns the PID of the daemon process.
a4952679 505
4327fe98 506=item B<save_pid>
a4952679 507
4327fe98 508Write the pidfile.
509
510=item B<remove_pid>
511
512Removes the pidfile.
513
514=back
515
516=head2 Signal Handling Methods
517
518=over 4
519
520=item B<setup_signals>
521
5b9ebe08 522Setup the signal handlers, by default it only sets up handlers for SIGINT and
4327fe98 523SIGHUP. If you wish to add more signals just use the C<after> method modifier
524and add them.
525
526=item B<handle_sigint>
a4952679 527
cecbee2d 528Handle a INT signal, by default calls C<$self->stop()>
a4952679 529
4327fe98 530=item B<handle_sighup>
a4952679 531
cecbee2d 532Handle a HUP signal. By default calls C<$self->restart()>
a4952679 533
4327fe98 534=back
535
9c8a33b3 536=head2 Exit Code Methods
537
538These are overriable constant methods used for setting the exit code.
539
540=over 4
541
542=item OK
543
544Returns 0.
545
546=item ERROR
547
548Returns 1.
549
550=back
551
4327fe98 552=head2 Introspection
553
554=over 4
555
a4952679 556=item meta()
557
cecbee2d 558The C<meta()> method from L<Class::MOP::Class>
a4952679 559
560=back
561
562=head1 DEPENDENCIES
563
4327fe98 564L<Moose>, L<MooseX::Getopt>, L<MooseX::Types::Path::Class> and L<POSIX>
a4952679 565
566=head1 INCOMPATIBILITIES
567
4327fe98 568None reported. Although obviously this will not work on Windows.
a4952679 569
570=head1 BUGS AND LIMITATIONS
571
a4952679 572No bugs have been reported.
573
574Please report any bugs or feature requests to
575C<bug-acme-dahut-call@rt.cpan.org>, or through the web interface at
576L<http://rt.cpan.org>.
577
578=head1 SEE ALSO
579
92b4ca7e 580L<Daemon::Control>, L<Proc::Daemon>, L<Daemon::Generic>
a4952679 581
92cf56b7 582=head1 AUTHORS
a4952679 583
69186a48 584Chris Prather C<< <chris@prather.org >>
a4952679 585
92cf56b7 586Stevan Little C<< <stevan.little@iinteractive.com> >>
587
7ada91b8 588=head1 THANKS
589
5b9ebe08 590Mike Boyko, Matt S. Trout, Stevan Little, Brandon Black, Ash Berlin and the
b916501e 591#moose denzians
a4952679 592
637573c4 593Some bug fixes sponsored by Takkle Inc.
594
a4952679 595=head1 LICENCE AND COPYRIGHT
596
05b96f4d 597Copyright (c) 2007-2011, Chris Prather C<< <chris@prather.org> >>. Some rights
b916501e 598reserved.
a4952679 599
600This module is free software; you can redistribute it and/or
601modify it under the same terms as Perl itself. See L<perlartistic>.
602
a4952679 603=head1 DISCLAIMER OF WARRANTY
604
605BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
606FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
607OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
608PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
609EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
610WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
611ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
612YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
613NECESSARY SERVICING, REPAIR, OR CORRECTION.
614
615IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
616WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
617REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
618LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
619OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
620THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
621RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
622FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
623SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
624SUCH DAMAGES.
8ac4733f 625
626=cut