2a12ce8cde94cd85b665f6522df4cfcf792ad097
[gitmo/MooseX-Daemonize.git] / lib / MooseX / Daemonize.pm
1 package MooseX::Daemonize;
2 use strict;    # because Kwalitee is pedantic
3 use Moose::Role;
4
5 our $VERSION = 0.02;
6 use Carp;
7 use Proc::Daemon;
8
9 use File::Pid;
10 use Moose::Util::TypeConstraints;
11
12 with qw(MooseX::Getopt);
13
14 has progname => (
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     },
23 );
24
25 has basedir => (
26     isa      => 'Str',
27     is       => 'ro',
28     required => 1,
29     lazy     => 1,
30     default  => sub { return '/' },
31 );
32
33 has pidbase => (
34     isa      => 'Str',
35     is       => 'ro',
36     lazy     => 1,
37     required => 1,
38     default  => sub { return '/var/run' },
39 );
40
41 subtype 'Pidfile' => as 'Object' => where { $_->isa('File::Pid') };
42
43 coerce 'Pidfile' => from 'Str' => via { File::Pid->new( { file => $_, } ); };
44
45 has pidfile => (
46     isa       => 'Pidfile',
47     is        => 'rw',
48     lazy      => 1,
49     required  => 1,
50     coerce    => 1,
51     predicate => 'has_pidfile',
52     default   => sub {
53         die 'Cannot write to ' . $_[0]->pidbase unless -w $_[0]->pidbase;
54         my $file = $_[0]->pidbase . '/' . $_[0]->progname . '.pid';
55         File::Pid->new( { file => $file } );
56     },
57     handles => {
58         check      => 'running',
59         save_pid   => 'write',
60         remove_pid => 'remove',
61         get_pid    => 'pid',
62         _pidfile   => 'file',
63     },
64 );
65
66 has foreground => (
67     metaclass   => 'MooseX::Getopt::Meta::Attribute',
68     cmd_aliases => 'f',
69     isa         => 'Bool',
70     is          => 'ro',
71     default     => sub { 0 },
72 );
73
74 has is_daemon => (
75     isa     => 'Bool',
76     is      => 'rw',
77     default => sub { 0 },
78 );
79
80 sub daemonize {
81     my ($self) = @_;
82     return if Proc::Daemon::Fork;
83     Proc::Daemon::Init;
84     $self->is_daemon(1);
85 }
86
87 sub start {
88     my ($self) = @_;
89     confess "instance already running" if $self->check;
90     $self->daemonize unless $self->foreground;
91
92     return unless $self->is_daemon;
93
94     $self->pidfile->pid($$);
95
96     # Avoid 'stdin reopened for output' warning with newer perls
97     ## no critic
98     open( NULL, '/dev/null' );
99     <NULL> if (0);
100     ## use critic
101
102     # Change to basedir
103     chdir $self->basedir;
104
105     $self->save_pid;
106     $self->setup_signals;
107     return $$;
108 }
109
110 sub stop {
111     my ( $self, %args ) = @_;
112     my $pid = $self->get_pid;
113     $self->_kill($pid) unless $self->foreground();
114     $self->remove_pid;
115     return 1 if $args{no_exit};
116     exit;
117 }
118
119 sub restart {
120     my ($self) = @_;
121     $self->stop( no_exit => 1 );
122     $self->start();
123 }
124
125 sub setup_signals {
126     my ($self) = @_;
127     $SIG{INT} = sub { $self->handle_sigint; };
128     $SIG{HUP} = sub { $self->handle_sighup };
129 }
130
131 sub handle_sigint { $_[0]->stop; }
132 sub handle_sighup { $_[0]->restart; }
133
134 sub _kill {
135     confess "_kill isn't public" unless caller eq __PACKAGE__;
136     my ( $self, $pid ) = @_;
137     return unless $pid;
138     unless ( CORE::kill 0 => $pid ) {
139
140         # warn "$pid already appears dead.";
141         return;
142     }
143
144     if ( $pid eq $$ ) {
145
146         # warn "$pid is us! Can't commit suicied.";
147         return;
148     }
149
150     CORE::kill( 2, $pid );    # Try SIGINT
151     sleep(2) if CORE::kill( 0, $pid );
152
153     unless ( CORE::kill 0 => $pid or $!{EPERM} ) {    # IF it is still running
154         CORE::kill( 15, $pid );                       # try SIGTERM
155         sleep(2) if CORE::kill( 0, $pid );
156     }
157
158     unless ( CORE::kill 0 => $pid or $!{EPERM} ) {    # IF it is still running
159         CORE::kill( 9, $pid );                        # finally try SIGKILL
160         sleep(3) if CORE::kill( 0, $pid );
161     }
162
163     unless ( CORE::kill 0 => $pid or $!{EPERM} ) {    # IF it is still running
164         carp "$pid doesn't seem to want to die.";     # AHH EVIL DEAD!
165     }
166
167     return;
168 }
169
170 1;
171 __END__
172
173 =head1 NAME
174
175 MooseX::Daemonize - provides a Role that daemonizes your Moose based application.
176
177
178 =head1 VERSION
179
180 This document describes MooseX::Daemonize version 0.0.1
181
182
183 =head1 SYNOPSIS
184
185     package FileMaker;
186     use Moose;
187     with qw(MooseX::Daemonize);
188
189     sub create_file {
190         my ( $self, $file ) = @_;
191         open( FILE, ">$file" ) || die;
192         close(FILE);
193     }
194
195     no Moose;
196
197     # then in the main package ... 
198     
199     my $daemon = FileMaker->new();
200     $daemon->start();
201     $daemon->create_file($file);
202     $daemon->stop();
203      
204 =head1 DESCRIPTION
205
206 Often you want to write a persistant daemon that has a pid file, and responds appropriately to Signals. 
207 This module helps provide the basic infrastructure to do that.
208
209 =head1 ATTRIBUTES
210
211 =over
212
213 =item progname Str
214
215 The name of our daemon, defaults to $self->meta->name =~ s/::/_/;
216
217 =item pidbase Str
218
219 The base for our bid, defaults to /var/run/$progname
220
221 =item pidfile Str
222
223 The file we store our PID in, defaults to /var/run/$progname/ 
224
225 =item foreground Bool
226
227 If true, the process won't background. Useful for debugging. This option can be set via Getopt's -f.
228
229 =back
230
231 =head1 METHODS 
232
233 =over
234
235 =item check()
236
237 Check to see if an instance is already running.
238
239 =item start()
240
241 Setup a pidfile, fork, then setup the signal handlers.
242
243 =item stop()
244
245 Stop the process matching the pidfile, and unlinks the pidfile.
246
247 =item restart()
248
249 Litterally 
250
251     $self->stop();
252     $self->start();
253
254 =item daemonize()
255
256 Calls C<Proc::Daemon::Init> to daemonize this process. 
257
258 =item kill($pid)
259
260 Kills the process for $pid. This will try SIGINT, and SIGTERM before falling back to SIGKILL and finally giving up.
261
262 =item setup_signals()
263
264 Setup the signal handlers, by default it only sets up handlers for SIGINT and SIGHUP
265
266 =item handle_sigint()
267
268 Handle a INT signal, by default calls C<$self->stop()>
269
270 =item handle_sighup()
271
272 Handle a HUP signal. By default calls C<$self->restart()>
273
274 =item get_pid
275
276 Lookup the pid from our pidfile.
277
278 =item save_pid
279
280 Save the current pid in our pidfile
281
282 =item remove_pid
283
284 Delete our pidfile
285
286 =item meta()
287
288 The C<meta()> method from L<Class::MOP::Class>
289
290 =back
291
292 =head1 DEPENDENCIES
293
294 =for author to fill in:
295     A list of all the other modules that this module relies upon,
296     including any restrictions on versions, and an indication whether
297     the module is part of the standard Perl distribution, part of the
298     module's distribution, or must be installed separately. ]
299
300 Obviously L<Moose>, also L<Carp>, L<Proc::Daemon>, L<File::Pid>
301
302 =head1 INCOMPATIBILITIES
303
304 =for author to fill in:
305     A list of any modules that this module cannot be used in conjunction
306     with. This may be due to name conflicts in the interface, or
307     competition for system or program resources, or due to internal
308     limitations of Perl (for example, many modules that use source code
309     filters are mutually incompatible).
310
311 None reported.
312
313
314 =head1 BUGS AND LIMITATIONS
315
316 =for author to fill in:
317     A list of known problems with the module, together with some
318     indication Whether they are likely to be fixed in an upcoming
319     release. Also a list of restrictions on the features the module
320     does provide: data types that cannot be handled, performance issues
321     and the circumstances in which they may arise, practical
322     limitations on the size of data sets, special cases that are not
323     (yet) handled, etc.
324
325 No bugs have been reported.
326
327 Please report any bugs or feature requests to
328 C<bug-acme-dahut-call@rt.cpan.org>, or through the web interface at
329 L<http://rt.cpan.org>.
330
331 =head1 SEE ALSO
332
333 L<Proc::Daemon>, L<Daemon::Generic>, L<MooseX::Getopt>
334
335 =head1 AUTHOR
336
337 Chris Prather  C<< <perigrin@cpan.org> >>
338
339 =head1 THANKS
340
341 Mike Boyko, Matt S. Trout, Stevan Little, Brandon Black, and the #moose denzians
342
343 =head1 LICENCE AND COPYRIGHT
344
345 Copyright (c) 2007, Chris Prather C<< <perigrin@cpan.org> >>. All rights 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.