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