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