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