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