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