Fix logic in _kill
[gitmo/MooseX-Daemonize.git] / lib / MooseX / Daemonize.pm
CommitLineData
a4952679 1package MooseX::Daemonize;
a392fa53 2use strict; # because Kwalitee is pedantic
a4952679 3use Moose::Role;
4
b916501e 5our $VERSION = 0.04;
a4952679 6use Carp;
7use Proc::Daemon;
a392fa53 8
fa2b72a4 9use File::Pid;
10use Moose::Util::TypeConstraints;
a4952679 11
12with qw(MooseX::Getopt);
13
14has progname => (
a392fa53 15 isa => 'Str',
16 is => 'ro',
17 lazy => 1,
18 required => 1,
19 default => sub {
20 ( my $name = lc $_[0]->meta->name ) =~ s/::/_/g;
21 return $name;
22 },
a4952679 23);
24
24a6a660 25has basedir => (
cbff8e52 26 isa => 'Str',
27 is => 'ro',
28 required => 1,
29 lazy => 1,
30 default => sub { return '/' },
24a6a660 31);
32
a4952679 33has pidbase => (
cbff8e52 34 isa => 'Str',
35 is => 'ro',
36 lazy => 1,
37 required => 1,
38 default => sub { return '/var/run' },
a4952679 39);
40
fa2b72a4 41subtype 'Pidfile' => as 'Object' => where { $_->isa('File::Pid') };
cbff8e52 42
43coerce 'Pidfile' => from 'Str' => via { File::Pid->new( { file => $_, } ); };
fa2b72a4 44
a4952679 45has pidfile => (
cbff8e52 46 isa => 'Pidfile',
47 is => 'rw',
48 lazy => 1,
49 required => 1,
50 coerce => 1,
51 predicate => 'has_pidfile',
52 default => sub {
fa2b72a4 53 my $file = $_[0]->pidbase . '/' . $_[0]->progname . '.pid';
e7a196e7 54 die "Cannot write to $file" unless (-e $file ? -w $file : -w $_[0]->pidbase);
fa2b72a4 55 File::Pid->new( { file => $file } );
56 },
57 handles => {
58 check => 'running',
59 save_pid => 'write',
60 remove_pid => 'remove',
61 get_pid => 'pid',
cbff8e52 62 _pidfile => 'file',
3543c999 63 },
a4952679 64);
65
66has foreground => (
cbff8e52 67 metaclass => 'MooseX::Getopt::Meta::Attribute',
68 cmd_aliases => 'f',
a4952679 69 isa => 'Bool',
70 is => 'ro',
71 default => sub { 0 },
72);
73
cbff8e52 74has is_daemon => (
75 isa => 'Bool',
76 is => 'rw',
77 default => sub { 0 },
78);
79
b916501e 80has stop_timeout => (
81 isa => 'Int',
82 is => 'rw',
83 default => 2
84);
85
a392fa53 86sub daemonize {
87 my ($self) = @_;
cbff8e52 88 return if Proc::Daemon::Fork;
a392fa53 89 Proc::Daemon::Init;
cbff8e52 90 $self->is_daemon(1);
a392fa53 91}
92
a4952679 93sub start {
94 my ($self) = @_;
cbff8e52 95 confess "instance already running" if $self->check;
a4952679 96 $self->daemonize unless $self->foreground;
97
cbff8e52 98 return unless $self->is_daemon;
99
100 $self->pidfile->pid($$);
101
3543c999 102 # Avoid 'stdin reopened for output' warning with newer perls
0585edbb 103 ## no critic
3543c999 104 open( NULL, '/dev/null' );
105 <NULL> if (0);
0585edbb 106 ## use critic
fa2b72a4 107
24a6a660 108 # Change to basedir
109 chdir $self->basedir;
fa2b72a4 110
3543c999 111 $self->save_pid;
112 $self->setup_signals;
113 return $$;
114}
115
b916501e 116# Make _kill *really* private
117my $_kill;
118
3543c999 119sub stop {
120 my ( $self, %args ) = @_;
121 my $pid = $self->get_pid;
b916501e 122 $self->$_kill($pid) unless $self->foreground();
3543c999 123 $self->remove_pid;
124 return 1 if $args{no_exit};
125 exit;
126}
127
a4952679 128sub restart {
129 my ($self) = @_;
7ada91b8 130 $self->stop( no_exit => 1 );
a4952679 131 $self->start();
132}
133
a4952679 134sub setup_signals {
3543c999 135 my ($self) = @_;
136 $SIG{INT} = sub { $self->handle_sigint; };
137 $SIG{HUP} = sub { $self->handle_sighup };
a4952679 138}
139
2361a590 140sub handle_sigint { $_[0]->stop; }
141sub handle_sighup { $_[0]->restart; }
a4952679 142
b916501e 143$_kill = sub {
a4952679 144 my ( $self, $pid ) = @_;
2361a590 145 return unless $pid;
3543c999 146 unless ( CORE::kill 0 => $pid ) {
147
148 # warn "$pid already appears dead.";
149 return;
150 }
151
152 if ( $pid eq $$ ) {
153
b916501e 154 # warn "$pid is us! Can't commit suicide.";
a4952679 155 return;
156 }
157
b916501e 158 my $timeout = $self->stop_timeout;
a4952679 159
b916501e 160 # kill 0 => $pid returns 0 if the process is dead
161 # $!{EPERM} could also be true if we cant kill it (permission error)
a4952679 162
b916501e 163 # Try SIGINT ... 2s ... SIGTERM ... 2s ... SIGKILL ... 3s ... UNDEAD!
164 for ( [ 2, $timeout ], [15, $timeout], [9, $timeout * 1.5] ) {
165 my ($signal, $timeout) = @$_;
166 $timeout = int $timeout;
167
168 CORE::kill($signal, $pid);
169
170 last unless CORE::kill 0 => $pid or $!{EPERM};
a4952679 171
b916501e 172 while ($timeout) {
173 sleep(1);
174 last unless CORE::kill 0 => $pid or $!{EPERM};
175 $timeout--;
176 }
a4952679 177 }
178
b916501e 179 return unless ( CORE::kill 0 => $pid or $!{EPERM} );
180
181 # IF it is still running
182 carp "$pid doesn't seem to want to die."; # AHH EVIL DEAD!
183};
a4952679 184
1851;
186__END__
187
a4952679 188=head1 NAME
189
b916501e 190MooseX::Daemonize - provides a Role that daemonizes your Moose based
191application.
a4952679 192
193=head1 VERSION
194
b916501e 195This document describes MooseX::Daemonize version 0.04
a4952679 196
197=head1 SYNOPSIS
198
199 package FileMaker;
200 use Moose;
201 with qw(MooseX::Daemonize);
202
203 sub create_file {
204 my ( $self, $file ) = @_;
205 open( FILE, ">$file" ) || die;
206 close(FILE);
207 }
208
209 no Moose;
210
211 # then in the main package ...
212
213 my $daemon = FileMaker->new();
214 $daemon->start();
215 $daemon->create_file($file);
216 $daemon->stop();
217
218=head1 DESCRIPTION
219
b916501e 220Often you want to write a persistant daemon that has a pid file, and responds
221appropriately to Signals. This module helps provide the basic infrastructure
222to do that.
a4952679 223
224=head1 ATTRIBUTES
225
226=over
227
228=item progname Str
229
cbff8e52 230The name of our daemon, defaults to $self->meta->name =~ s/::/_/;
a4952679 231
232=item pidbase Str
233
234The base for our bid, defaults to /var/run/$progname
235
236=item pidfile Str
237
238The file we store our PID in, defaults to /var/run/$progname/
239
240=item foreground Bool
241
b916501e 242If true, the process won't background. Useful for debugging. This option can
243be set via Getopt's -f.
a4952679 244
e7a196e7 245=item is_daemon Bool
246
b916501e 247If true, the process is the backgrounded process. This is useful for example
248in an after 'start' => sub { } block
249
250=item stop_timeout
251
252Number of seconds to wait for the process to stop, before trying harder to kill
253it. Defaults to 2 seconds
e7a196e7 254
a4952679 255=back
256
257=head1 METHODS
258
259=over
260
261=item check()
262
263Check to see if an instance is already running.
264
265=item start()
266
267Setup a pidfile, fork, then setup the signal handlers.
268
269=item stop()
270
271Stop the process matching the pidfile, and unlinks the pidfile.
272
273=item restart()
274
275Litterally
276
277 $self->stop();
278 $self->start();
279
280=item daemonize()
281
282Calls C<Proc::Daemon::Init> to daemonize this process.
283
a4952679 284=item setup_signals()
285
286Setup the signal handlers, by default it only sets up handlers for SIGINT and SIGHUP
287
288=item handle_sigint()
289
cecbee2d 290Handle a INT signal, by default calls C<$self->stop()>
a4952679 291
292=item handle_sighup()
293
cecbee2d 294Handle a HUP signal. By default calls C<$self->restart()>
a4952679 295
3543c999 296=item get_pid
297
cecbee2d 298Lookup the pid from our pidfile.
299
3543c999 300=item save_pid
301
cecbee2d 302Save the current pid in our pidfile
303
3543c999 304=item remove_pid
305
cecbee2d 306Delete our pidfile
307
a4952679 308=item meta()
309
cecbee2d 310The C<meta()> method from L<Class::MOP::Class>
a4952679 311
312=back
313
314=head1 DEPENDENCIES
315
316=for author to fill in:
317 A list of all the other modules that this module relies upon,
318 including any restrictions on versions, and an indication whether
319 the module is part of the standard Perl distribution, part of the
320 module's distribution, or must be installed separately. ]
321
fa2b72a4 322Obviously L<Moose>, also L<Carp>, L<Proc::Daemon>, L<File::Pid>
a4952679 323
324=head1 INCOMPATIBILITIES
325
326=for author to fill in:
327 A list of any modules that this module cannot be used in conjunction
328 with. This may be due to name conflicts in the interface, or
329 competition for system or program resources, or due to internal
330 limitations of Perl (for example, many modules that use source code
331 filters are mutually incompatible).
332
333None reported.
334
335
336=head1 BUGS AND LIMITATIONS
337
338=for author to fill in:
339 A list of known problems with the module, together with some
340 indication Whether they are likely to be fixed in an upcoming
341 release. Also a list of restrictions on the features the module
342 does provide: data types that cannot be handled, performance issues
343 and the circumstances in which they may arise, practical
344 limitations on the size of data sets, special cases that are not
345 (yet) handled, etc.
346
347No bugs have been reported.
348
349Please report any bugs or feature requests to
350C<bug-acme-dahut-call@rt.cpan.org>, or through the web interface at
351L<http://rt.cpan.org>.
352
353=head1 SEE ALSO
354
355L<Proc::Daemon>, L<Daemon::Generic>, L<MooseX::Getopt>
356
357=head1 AUTHOR
358
359Chris Prather C<< <perigrin@cpan.org> >>
360
7ada91b8 361=head1 THANKS
362
b916501e 363Mike Boyko, Matt S. Trout, Stevan Little, Brandon Black, Ash Berlin and the
364#moose denzians
a4952679 365
366=head1 LICENCE AND COPYRIGHT
367
b916501e 368Copyright (c) 2007, Chris Prather C<< <perigrin@cpan.org> >>. All rights
369reserved.
a4952679 370
371This module is free software; you can redistribute it and/or
372modify it under the same terms as Perl itself. See L<perlartistic>.
373
374
375=head1 DISCLAIMER OF WARRANTY
376
377BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
378FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
379OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
380PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
381EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
382WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
383ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
384YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
385NECESSARY SERVICING, REPAIR, OR CORRECTION.
386
387IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
388WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
389REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
390LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
391OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
392THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
393RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
394FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
395SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
396SUCH DAMAGES.