put strictures before package statement
[gitmo/MooseX-Daemonize.git] / lib / MooseX / Daemonize.pm
CommitLineData
5231273c 1use strict;
2use warnings;
a4952679 3package MooseX::Daemonize;
5231273c 4
a4952679 5use Moose::Role;
8ac4733f 6use MooseX::Types::Path::Class;
e803cff5 7use File::Path qw(make_path);
a392fa53 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
b37fcc5f 218 # then we don't need to stop
5b9ebe08 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
1c60dcf3 320=head1 WARNING
321
322The maintainers of this module now recommend using L<Daemon::Control> instead.
323
a4952679 324=head1 SYNOPSIS
325
4327fe98 326 package My::Daemon;
a4952679 327 use Moose;
5b9ebe08 328
a4952679 329 with qw(MooseX::Daemonize);
5b9ebe08 330
4327fe98 331 # ... define your class ....
5b9ebe08 332
333 after start => sub {
4327fe98 334 my $self = shift;
335 return unless $self->is_daemon;
336 # your daemon code here ...
337 };
a4952679 338
5b9ebe08 339 # then in your script ...
340
4327fe98 341 my $daemon = My::Daemon->new_with_options();
5b9ebe08 342
4327fe98 343 my ($command) = @{$daemon->extra_argv}
344 defined $command || die "No command specified";
5b9ebe08 345
346 $daemon->start if $command eq 'start';
347 $daemon->status if $command eq 'status';
348 $daemon->restart if $command eq 'restart';
349 $daemon->stop if $command eq 'stop';
350
92cf56b7 351 warn($daemon->status_message);
5b9ebe08 352 exit($daemon->exit_code);
353
a4952679 354=head1 DESCRIPTION
355
b37fcc5f 356Often you want to write a persistent daemon that has a pid file, and responds
5b9ebe08 357appropriately to Signals. This module provides a set of basic roles as an
4327fe98 358infrastructure to do that.
a4952679 359
05b96f4d 360=head1 CAVEATS
361
362When going into background MooseX::Daemonize closes all open file
363handles. This may interfere with you logging because it may also close the log
364file handle you want to write to. To prevent this you can either defer opening
365the log file until after start. Alternatively, use can use the
366'dont_close_all_files' option either from the command line or in your .sh
367script.
368
369Assuming you want to use Log::Log4perl for example you could expand the
370MooseX::Daemonize example above like this.
371
372 after start => sub {
373 my $self = shift;
374 return unless $self->is_daemon;
375 Log::Log4perl->init(\$log4perl_config);
376 my $logger = Log::Log4perl->get_logger();
377 $logger->info("Daemon started");
378 # your daemon code here ...
379 };
380
381
a4952679 382=head1 ATTRIBUTES
383
4327fe98 384This list includes attributes brought in from other roles as well
385we include them here for ease of documentation. All of these attributes
5b9ebe08 386are settable though L<MooseX::Getopt>'s command line handling, with the
4327fe98 387exception of C<is_daemon>.
388
a4952679 389=over
390
4327fe98 391=item I<progname Path::Class::Dir | Str>
a4952679 392
4327fe98 393The name of our daemon, defaults to C<$package_name =~ s/::/_/>;
a4952679 394
4327fe98 395=item I<pidbase Path::Class::Dir | Str>
a4952679 396
1d85c76d 397The base for our PID, defaults to C</var/run/>
a4952679 398
f453ca7b 399=item I<basedir Path::Class::Dir | Str>
400
401The directory we chdir to; defaults to C</>.
402
4327fe98 403=item I<pidfile MooseX::Daemonize::Pid::File | Str>
a4952679 404
1d85c76d 405The file we store our PID in, defaults to C<$pidbase/$progname.pid>
a4952679 406
4327fe98 407=item I<foreground Bool>
a4952679 408
5b9ebe08 409If true, the process won't background. Useful for debugging. This option can
b916501e 410be set via Getopt's -f.
a4952679 411
2ecc2ccb 412=item I<no_double_fork Bool>
413
414If true, the process will not perform the typical double-fork, which is extra
b37fcc5f 415added protection from your process accidentally acquiring a controlling terminal.
2ecc2ccb 416More information can be found by Googling "double fork daemonize".
417
418=item I<ignore_zombies Bool>
419
420If true, the process will not clean up zombie processes.
421Normally you don't want this.
422
423=item I<dont_close_all_files Bool>
424
425If true, the objects open filehandles will not be closed when daemonized.
426Normally you don't want this.
427
428
4327fe98 429=item I<is_daemon Bool>
430
5b9ebe08 431If true, the process is the backgrounded daemon process, if false it is the
432parent process. This is useful for example in an C<after 'start' => sub { }>
433block.
e7a196e7 434
4327fe98 435B<NOTE:> This option is explicitly B<not> available through L<MooseX::Getopt>.
b916501e 436
4327fe98 437=item I<stop_timeout>
b916501e 438
439Number of seconds to wait for the process to stop, before trying harder to kill
4327fe98 440it. Defaults to 2 seconds.
e7a196e7 441
a4952679 442=back
443
5b9ebe08 444These are the internal attributes, which are not available through MooseX::Getopt.
445
446=over 4
447
448=item I<exit_code Int>
449
92cf56b7 450=item I<status_message Str>
5b9ebe08 451
452=back
453
454=head1 METHODS
a4952679 455
4327fe98 456=head2 Daemon Control Methods
457
5b9ebe08 458These methods can be used to control the daemon behavior. Every effort
459has been made to have these methods DWIM (Do What I Mean), so that you
460can focus on just writing the code for your daemon.
a4952679 461
5b9ebe08 462Extending these methods is best done with the L<Moose> method modifiers,
4327fe98 463such as C<before>, C<after> and C<around>.
464
465=over 4
466
467=item B<start>
a4952679 468
469Setup a pidfile, fork, then setup the signal handlers.
470
4327fe98 471=item B<stop>
a4952679 472
473Stop the process matching the pidfile, and unlinks the pidfile.
474
4327fe98 475=item B<restart>
a4952679 476
4327fe98 477Literally this is:
a4952679 478
479 $self->stop();
480 $self->start();
481
5b9ebe08 482=item B<status>
483
92cf56b7 484=item B<shutdown>
485
4327fe98 486=back
487
5b9ebe08 488
4327fe98 489=head2 Pidfile Handling Methods
490
491=over 4
492
493=item B<init_pidfile>
494
495This method will create a L<MooseX::Daemonize::Pid::File> object and tell
496it to store the PID in the file C<$pidbase/$progname.pid>.
497
498=item B<check>
499
5b9ebe08 500This checks to see if the daemon process is currently running by checking
4327fe98 501the pidfile.
a4952679 502
4327fe98 503=item B<get_pid>
a4952679 504
4327fe98 505Returns the PID of the daemon process.
a4952679 506
4327fe98 507=item B<save_pid>
a4952679 508
4327fe98 509Write the pidfile.
510
511=item B<remove_pid>
512
513Removes the pidfile.
514
515=back
516
517=head2 Signal Handling Methods
518
519=over 4
520
521=item B<setup_signals>
522
5b9ebe08 523Setup the signal handlers, by default it only sets up handlers for SIGINT and
4327fe98 524SIGHUP. If you wish to add more signals just use the C<after> method modifier
525and add them.
526
527=item B<handle_sigint>
a4952679 528
cecbee2d 529Handle a INT signal, by default calls C<$self->stop()>
a4952679 530
4327fe98 531=item B<handle_sighup>
a4952679 532
cecbee2d 533Handle a HUP signal. By default calls C<$self->restart()>
a4952679 534
4327fe98 535=back
536
9c8a33b3 537=head2 Exit Code Methods
538
b37fcc5f 539These are overridable constant methods used for setting the exit code.
9c8a33b3 540
541=over 4
542
543=item OK
544
545Returns 0.
546
547=item ERROR
548
549Returns 1.
550
551=back
552
4327fe98 553=head2 Introspection
554
555=over 4
556
a4952679 557=item meta()
558
cecbee2d 559The C<meta()> method from L<Class::MOP::Class>
a4952679 560
561=back
562
563=head1 DEPENDENCIES
564
4327fe98 565L<Moose>, L<MooseX::Getopt>, L<MooseX::Types::Path::Class> and L<POSIX>
a4952679 566
567=head1 INCOMPATIBILITIES
568
4327fe98 569None reported. Although obviously this will not work on Windows.
a4952679 570
571=head1 BUGS AND LIMITATIONS
572
a4952679 573No bugs have been reported.
574
575Please report any bugs or feature requests to
576C<bug-acme-dahut-call@rt.cpan.org>, or through the web interface at
577L<http://rt.cpan.org>.
578
579=head1 SEE ALSO
580
92b4ca7e 581L<Daemon::Control>, L<Proc::Daemon>, L<Daemon::Generic>
a4952679 582
92cf56b7 583=head1 AUTHORS
a4952679 584
69186a48 585Chris Prather C<< <chris@prather.org >>
a4952679 586
92cf56b7 587Stevan Little C<< <stevan.little@iinteractive.com> >>
588
7ada91b8 589=head1 THANKS
590
5b9ebe08 591Mike Boyko, Matt S. Trout, Stevan Little, Brandon Black, Ash Berlin and the
b916501e 592#moose denzians
a4952679 593
637573c4 594Some bug fixes sponsored by Takkle Inc.
595
a4952679 596=head1 LICENCE AND COPYRIGHT
597
05b96f4d 598Copyright (c) 2007-2011, Chris Prather C<< <chris@prather.org> >>. Some rights
b916501e 599reserved.
a4952679 600
601This module is free software; you can redistribute it and/or
602modify it under the same terms as Perl itself. See L<perlartistic>.
603
a4952679 604=head1 DISCLAIMER OF WARRANTY
605
606BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
607FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
608OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
609PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
610EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
611WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
612ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
613YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
614NECESSARY SERVICING, REPAIR, OR CORRECTION.
615
616IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
617WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
618REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
619LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
620OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
621THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
622RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
623FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
624SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
625SUCH DAMAGES.
8ac4733f 626
627=cut