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