File Coverage

blib/lib/MooseX/Daemonize.pm
Criterion Covered Total %
statement 70 97 72.1
branch 18 32 56.2
condition n/a
subroutine 13 18 72.2
pod 11 11 100.0
total 112 158 70.8


line stmt bran cond sub pod time code
1 8     8   527078 use strict;
  8         11  
  8         193  
2 8     8   23 use warnings;
  8         8  
  8         383  
3             package MooseX::Daemonize; # git description: v0.20-8-g6d23389
4             # ABSTRACT: Role for daemonizing your Moose based application
5              
6             our $VERSION = '0.21';
7              
8 8     8   1410 use Moose::Role;
  8         947678  
  8         32  
9 8     8   30279 use MooseX::Types::Path::Class;
  8         2195731  
  8         64  
10 8     8   5037 use File::Path qw(make_path);
  8         12  
  8         401  
11 8     8   33 use namespace::autoclean;
  8         8  
  8         46  
12              
13             with 'MooseX::Daemonize::WithPidFile',
14             'MooseX::Getopt';
15              
16             sub OK () { 0 }
17             sub ERROR () { 1 }
18              
19             has progname => (
20             metaclass => 'Getopt',
21             isa => 'Str',
22             is => 'ro',
23             lazy => 1,
24             required => 1,
25             default => sub {
26             ( my $name = lc $_[0]->meta->name ) =~ s/::/_/g;
27             return $name;
28             },
29             documentation => 'the name of the daemon',
30             );
31              
32             has pidbase => (
33             metaclass => 'Getopt',
34             isa => 'Path::Class::Dir',
35             is => 'ro',
36             coerce => 1,
37             required => 1,
38             lazy => 1,
39             default => sub { Path::Class::Dir->new('', 'var', 'run') },
40             documentation => 'the base for our pid (default: /var/run)',
41             );
42              
43             has basedir => (
44             metaclass => 'Getopt',
45             isa => 'Path::Class::Dir',
46             is => 'ro',
47             coerce => 1,
48             required => 1,
49             lazy => 1,
50             default => sub { Path::Class::Dir->new('/') },
51             documentation => 'the directory to chdir to (default: /)',
52             );
53              
54             has foreground => (
55             metaclass => 'Getopt',
56             cmd_aliases => 'f',
57             isa => 'Bool',
58             is => 'ro',
59             default => sub { 0 },
60             documentation => 'if true, the process won\'t background',
61             );
62              
63             has stop_timeout => (
64             metaclass => 'Getopt',
65             isa => 'Int',
66             is => 'rw',
67             default => sub { 2 },
68             documentation => 'number of seconds to wait for the process to stop, before trying harder to kill it (default: 2 s)',
69             );
70              
71             # internal book-keeping
72              
73             has status_message => (
74             metaclass => 'NoGetopt',
75             isa => 'Str',
76             is => 'rw',
77             clearer => 'clear_status_message',
78             );
79              
80             has exit_code => (
81             metaclass => 'NoGetopt',
82             isa => 'Int',
83             is => 'rw',
84             clearer => 'clear_exit_code',
85             );
86              
87             # methods ...
88              
89             ## PID file related stuff ...
90              
91             sub init_pidfile {
92 7     7 1 25 my $self = shift;
93 7         222 my $file = $self->pidbase . '/' . $self->progname . '.pid';
94              
95 7 100       208 if ( !-d $self->pidbase ) {
96 3         228 make_path( $self->pidbase, { error => \my $err } );
97 3 50       828 if (@$err) {
98 0         0 confess sprintf( "Cannot create pidbase directory '%s': %s",
99             $self->pidbase, @$err );
100             }
101             }
102              
103 7 100       624 confess "Cannot write to $file" unless (-e $file ? -w $file : -w $self->pidbase);
    50          
104 7         456 MooseX::Daemonize::Pid::File->new( file => $file );
105             }
106              
107             # backwards compat,
108 0     0 1 0 sub check { (shift)->pidfile->is_running }
109 0     0 1 0 sub save_pid { (shift)->pidfile->write }
110 0     0 1 0 sub remove_pid { (shift)->pidfile->remove }
111 0     0 1 0 sub get_pid { (shift)->pidfile->pid }
112              
113             ## signal handling ...
114              
115             sub setup_signals {
116 2     2 1 4 my $self = shift;
117 2     2   76 $SIG{'INT'} = sub { $self->shutdown };
  2         4568008  
118             # I can't think of a sane default here really ...
119             # $SIG{'HUP'} = sub { $self->handle_sighup };
120             }
121              
122             sub shutdown {
123 2     2 1 5 my $self = shift;
124 2 50       88 $self->pidfile->remove if $self->pidfile->pid == $$;
125 2         586 exit(0);
126             }
127              
128             ## daemon control methods ...
129              
130             sub start {
131 6     6 1 390 my $self = shift;
132              
133 6         615 $self->clear_status_message;
134 6         207 $self->clear_exit_code;
135              
136 6 50       201 if ($self->pidfile->is_running) {
137 0         0 $self->exit_code($self->OK);
138 0         0 $self->status_message('Daemon is already running with pid (' . $self->pidfile->pid . ')');
139 0         0 return !($self->exit_code);
140             }
141              
142 6 50       510 if ($self->foreground) {
143 0         0 $self->is_daemon(1);
144             }
145             else {
146 6         30 eval { $self->daemonize };
  6         33  
147 4 50       336 if ($@) {
148 0         0 $self->exit_code($self->ERROR);
149 0         0 $self->status_message('Start failed : ' . $@);
150 0         0 return !($self->exit_code);
151             }
152             }
153              
154 4 100       124 unless ($self->is_daemon) {
155 2         68 $self->exit_code($self->OK);
156 2         68 $self->status_message('Start succeeded');
157 2         50 return !($self->exit_code);
158             }
159              
160 2         88 $self->pidfile->pid($$);
161              
162             # Change to basedir
163 2         61 chdir $self->basedir;
164              
165 2         106 $self->pidfile->write;
166 2         69 $self->setup_signals;
167 2         12 return $$;
168             }
169              
170             sub status {
171 5     5 1 1220 my $self = shift;
172              
173 5         173 $self->clear_status_message;
174 5         124 $self->clear_exit_code;
175              
176 5 100       108 if ($self->pidfile->is_running) {
177 1         27 $self->exit_code($self->OK);
178 1         24 $self->status_message('Daemon is running with pid (' . $self->pidfile->pid . ')');
179             }
180             else {
181 4         304 $self->exit_code($self->ERROR);
182 4         84 $self->status_message('Daemon is not running with pid (' . $self->pidfile->pid . ')');
183             }
184              
185 5         102 return !($self->exit_code);
186             }
187              
188             sub restart {
189 0     0 1 0 my $self = shift;
190              
191 0         0 $self->clear_status_message;
192 0         0 $self->clear_exit_code;
193              
194 0 0       0 unless ($self->stop) {
195 0         0 $self->exit_code($self->ERROR);
196 0         0 $self->status_message('Restart (Stop) failed : ' . $@);
197             }
198              
199 0 0       0 unless ($self->start) {
200 0         0 $self->exit_code($self->ERROR);
201 0         0 $self->status_message('Restart (Start) failed : ' . $@);
202             }
203              
204 0 0       0 if ($self->exit_code == $self->OK) {
205 0         0 $self->exit_code($self->OK);
206 0         0 $self->status_message("Restart successful");
207             }
208              
209 0         0 return !($self->exit_code);
210             }
211              
212             # Make _kill *really* private
213             my $_kill;
214              
215             sub stop {
216 5     5 1 3001454 my $self = shift;
217              
218 5         209 $self->clear_status_message;
219 5         141 $self->clear_exit_code;
220              
221             # if the pid is not running
222             # then we don't need to stop
223             # anything ...
224 5 100       129 if ($self->pidfile->is_running) {
225              
226             # if we are foreground, then
227             # no need to try and kill
228             # ourselves
229 2 50       56 unless ($self->foreground) {
230              
231             # kill the process ...
232 2         6 eval { $self->$_kill($self->pidfile->pid) };
  2         47  
233             # and complain if we can't ...
234 2 50       13 if ($@) {
235 0         0 $self->exit_code($self->ERROR);
236 0         0 $self->status_message('Stop failed : ' . $@);
237             }
238             # or gloat if we succeed ..
239             else {
240 2         163 $self->exit_code($self->OK);
241 2         55 $self->status_message('Stop succeeded');
242             }
243              
244             }
245             }
246             else {
247             # this just returns the OK
248             # exit code for now, but
249             # we should make this overridable
250 3         183 $self->exit_code($self->OK);
251 3         63 $self->status_message("Not running");
252             }
253              
254             # if we are returning to our script
255             # then we actually need the opposite
256             # of what the system/OS expects
257 5         114 return !($self->exit_code);
258             }
259              
260             $_kill = sub {
261             my ( $self, $pid ) = @_;
262             return unless $pid;
263             unless ( CORE::kill 0 => $pid ) {
264             # warn "$pid already appears dead.";
265             return;
266             }
267              
268             if ( $pid eq $$ ) {
269             die "$pid is us! Can't commit suicide.";
270             }
271              
272             my $timeout = $self->stop_timeout;
273              
274             # kill 0 => $pid returns 0 if the process is dead
275             # $!{EPERM} could also be true if we cant kill it (permission error)
276              
277             # Try SIGINT ... 2s ... SIGTERM ... 2s ... SIGKILL ... 3s ... UNDEAD!
278             my $terminating_signal;
279             for ( [ 2, $timeout ], [15, $timeout], [9, $timeout * 1.5] ) {
280             my ($signal, $timeout) = @$_;
281             $timeout = int $timeout;
282              
283             CORE::kill($signal, $pid);
284              
285             while ($timeout) {
286             unless(CORE::kill 0 => $pid or $!{EPERM}) {
287             $terminating_signal = $signal;
288             last;
289             }
290             $timeout--;
291             sleep(1) if $timeout;
292             }
293              
294             last if $terminating_signal;
295             }
296              
297             if($terminating_signal) {
298             if($terminating_signal == 9) {
299             # clean up the pidfile ourselves iff we used -9 and it worked
300             warn "Had to resort to 'kill -9' and it worked, wiping pidfile";
301             eval { $self->pidfile->remove };
302             if ($@) {
303             warn "Could not remove pidfile ("
304             . $self->pidfile->file
305             . ") because : $!";
306             }
307             }
308             return;
309             }
310              
311             # IF it is still running
312             Carp::carp "$pid doesn't seem to want to die."; # AHH EVIL DEAD!
313             };
314              
315             1;
316              
317             __END__
318              
319             =pod
320              
321             =encoding UTF-8
322              
323             =head1 NAME
324              
325             MooseX::Daemonize - Role for daemonizing your Moose based application
326              
327             =head1 VERSION
328              
329             version 0.21
330              
331             =head1 SYNOPSIS
332              
333             package My::Daemon;
334             use Moose;
335              
336             with qw(MooseX::Daemonize);
337              
338             # ... define your class ....
339              
340             after start => sub {
341             my $self = shift;
342             return unless $self->is_daemon;
343             # your daemon code here ...
344             };
345              
346             # then in your script ...
347              
348             my $daemon = My::Daemon->new_with_options();
349              
350             my ($command) = @{$daemon->extra_argv}
351             defined $command || die "No command specified";
352              
353             $daemon->start if $command eq 'start';
354             $daemon->status if $command eq 'status';
355             $daemon->restart if $command eq 'restart';
356             $daemon->stop if $command eq 'stop';
357              
358             warn($daemon->status_message);
359             exit($daemon->exit_code);
360              
361             =head1 DESCRIPTION
362              
363             Often you want to write a persistent daemon that has a pid file, and responds
364             appropriately to Signals. This module provides a set of basic roles as an
365             infrastructure to do that.
366              
367             =head1 WARNING
368              
369             The maintainers of this module now recommend using L<Daemon::Control> instead.
370              
371             =head1 CAVEATS
372              
373             When going into background MooseX::Daemonize closes all open file
374             handles. This may interfere with you logging because it may also close the log
375             file handle you want to write to. To prevent this you can either defer opening
376             the log file until after start. Alternatively, use can use the
377             'dont_close_all_files' option either from the command line or in your .sh
378             script.
379              
380             Assuming you want to use Log::Log4perl for example you could expand the
381             MooseX::Daemonize example above like this.
382              
383             after start => sub {
384             my $self = shift;
385             return unless $self->is_daemon;
386             Log::Log4perl->init(\$log4perl_config);
387             my $logger = Log::Log4perl->get_logger();
388             $logger->info("Daemon started");
389             # your daemon code here ...
390             };
391              
392             =head1 ATTRIBUTES
393              
394             This list includes attributes brought in from other roles as well
395             we include them here for ease of documentation. All of these attributes
396             are settable though L<MooseX::Getopt>'s command line handling, with the
397             exception of C<is_daemon>.
398              
399             =over
400              
401             =item I<progname Path::Class::Dir | Str>
402              
403             The name of our daemon, defaults to C<$package_name =~ s/::/_/>;
404              
405             =item I<pidbase Path::Class::Dir | Str>
406              
407             The base for our PID, defaults to C</var/run/>
408              
409             =item I<basedir Path::Class::Dir | Str>
410              
411             The directory we chdir to; defaults to C</>.
412              
413             =item I<pidfile MooseX::Daemonize::Pid::File | Str>
414              
415             The file we store our PID in, defaults to C<$pidbase/$progname.pid>
416              
417             =item I<foreground Bool>
418              
419             If true, the process won't background. Useful for debugging. This option can
420             be set via Getopt's -f.
421              
422             =item I<no_double_fork Bool>
423              
424             If true, the process will not perform the typical double-fork, which is extra
425             added protection from your process accidentally acquiring a controlling terminal.
426             More information can be found by Googling "double fork daemonize".
427              
428             =item I<ignore_zombies Bool>
429              
430             If true, the process will not clean up zombie processes.
431             Normally you don't want this.
432              
433             =item I<dont_close_all_files Bool>
434              
435             If true, the objects open filehandles will not be closed when daemonized.
436             Normally you don't want this.
437              
438             =item I<is_daemon Bool>
439              
440             If true, the process is the backgrounded daemon process, if false it is the
441             parent process. This is useful for example in an C<after 'start' => sub { }>
442             block.
443              
444             B<NOTE:> This option is explicitly B<not> available through L<MooseX::Getopt>.
445              
446             =item I<stop_timeout>
447              
448             Number of seconds to wait for the process to stop, before trying harder to kill
449             it. Defaults to 2 seconds.
450              
451             =back
452              
453             These are the internal attributes, which are not available through MooseX::Getopt.
454              
455             =over 4
456              
457             =item I<exit_code Int>
458              
459             =item I<status_message Str>
460              
461             =back
462              
463             =head1 METHODS
464              
465             =head2 Daemon Control Methods
466              
467             These methods can be used to control the daemon behavior. Every effort
468             has been made to have these methods DWIM (Do What I Mean), so that you
469             can focus on just writing the code for your daemon.
470              
471             Extending these methods is best done with the L<Moose> method modifiers,
472             such as C<before>, C<after> and C<around>.
473              
474             =over 4
475              
476             =item B<start>
477              
478             Setup a pidfile, fork, then setup the signal handlers.
479              
480             =item B<stop>
481              
482             Stop the process matching the pidfile, and unlinks the pidfile.
483              
484             =item B<restart>
485              
486             Literally this is:
487              
488             $self->stop();
489             $self->start();
490              
491             =item B<status>
492              
493             =item B<shutdown>
494              
495             =back
496              
497             =head2 Pidfile Handling Methods
498              
499             =over 4
500              
501             =item B<init_pidfile>
502              
503             This method will create a L<MooseX::Daemonize::Pid::File> object and tell
504             it to store the PID in the file C<$pidbase/$progname.pid>.
505              
506             =item B<check>
507              
508             This checks to see if the daemon process is currently running by checking
509             the pidfile.
510              
511             =item B<get_pid>
512              
513             Returns the PID of the daemon process.
514              
515             =item B<save_pid>
516              
517             Write the pidfile.
518              
519             =item B<remove_pid>
520              
521             Removes the pidfile.
522              
523             =back
524              
525             =head2 Signal Handling Methods
526              
527             =over 4
528              
529             =item B<setup_signals>
530              
531             Setup the signal handlers, by default it only sets up handlers for SIGINT and
532             SIGHUP. If you wish to add more signals just use the C<after> method modifier
533             and add them.
534              
535             =item B<handle_sigint>
536              
537             Handle a INT signal, by default calls C<$self->stop()>
538              
539             =item B<handle_sighup>
540              
541             Handle a HUP signal. By default calls C<$self->restart()>
542              
543             =back
544              
545             =head2 Exit Code Methods
546              
547             These are overridable constant methods used for setting the exit code.
548              
549             =over 4
550              
551             =item OK
552              
553             Returns 0.
554              
555             =item ERROR
556              
557             Returns 1.
558              
559             =back
560              
561             =head2 Introspection
562              
563             =over 4
564              
565             =item meta()
566              
567             The C<meta()> method from L<Class::MOP::Class>
568              
569             =back
570              
571             =head1 DEPENDENCIES
572              
573             L<Moose>, L<MooseX::Getopt>, L<MooseX::Types::Path::Class> and L<POSIX>
574              
575             =head1 INCOMPATIBILITIES
576              
577             Obviously this will not work on Windows.
578              
579             =head1 SEE ALSO
580              
581             L<Daemon::Control>, L<Proc::Daemon>, L<Daemon::Generic>
582              
583             =head1 THANKS
584              
585             Mike Boyko, Matt S. Trout, Stevan Little, Brandon Black, Ash Berlin and the
586             #moose denizens
587              
588             Some bug fixes sponsored by Takkle Inc.
589              
590             =head1 SUPPORT
591              
592             Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=MooseX-Daemonize>
593             (or L<bug-MooseX-Daemonize@rt.cpan.org|mailto:bug-MooseX-Daemonize@rt.cpan.org>).
594              
595             There is also a mailing list available for users of this distribution, at
596             L<http://lists.perl.org/list/moose.html>.
597              
598             There is also an irc channel available for users of this distribution, at
599             L<C<#moose> on C<irc.perl.org>|irc://irc.perl.org/#moose>.
600              
601             =head1 AUTHORS
602              
603             =over 4
604              
605             =item *
606              
607             Stevan Little <stevan.little@iinteractive.com>
608              
609             =item *
610              
611             Chris Prather <chris@prather.org>
612              
613             =back
614              
615             =head1 CONTRIBUTORS
616              
617             =for stopwords Karen Etheridge Michael Reddick Yuval Kogman Ash Berlin Brandon L Black David Steinbrunner Dave Rolsky Chisel Wright
618              
619             =over 4
620              
621             =item *
622              
623             Karen Etheridge <ether@cpan.org>
624              
625             =item *
626              
627             Michael Reddick <michael.reddick@gmail.com>
628              
629             =item *
630              
631             Yuval Kogman <nothingmuch@woobling.org>
632              
633             =item *
634              
635             Ash Berlin <ash@cpan.org>
636              
637             =item *
638              
639             Brandon L Black <blblack@gmail.com>
640              
641             =item *
642              
643             David Steinbrunner <dsteinbrunner@pobox.com>
644              
645             =item *
646              
647             Dave Rolsky <autarch@urth.org>
648              
649             =item *
650              
651             Chisel Wright <chisel@chizography.net>
652              
653             =back
654              
655             =head1 COPYRIGHT AND LICENCE
656              
657             This software is copyright (c) 2007 by Chris Prather.
658              
659             This is free software; you can redistribute it and/or modify it under
660             the same terms as the Perl 5 programming language system itself.
661              
662             =cut