add Test::MooseX::Daemonize
[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
a4952679 139=head1 NAME
140
141MooseX::Daemonize - provides a Role that daemonizes your Moose based application.
142
143
144=head1 VERSION
145
146This document describes MooseX::Daemonize version 0.0.1
147
148
149=head1 SYNOPSIS
150
151 package FileMaker;
152 use Moose;
153 with qw(MooseX::Daemonize);
154
155 sub create_file {
156 my ( $self, $file ) = @_;
157 open( FILE, ">$file" ) || die;
158 close(FILE);
159 }
160
161 no Moose;
162
163 # then in the main package ...
164
165 my $daemon = FileMaker->new();
166 $daemon->start();
167 $daemon->create_file($file);
168 $daemon->stop();
169
170=head1 DESCRIPTION
171
172Often you want to write a persistant daemon that has a pid file, and responds appropriately to Signals.
173This module helps provide the basic infrastructure to do that.
174
175=head1 ATTRIBUTES
176
177=over
178
179=item progname Str
180
181The name of our daemon, defaults to $0
182
183=item pidbase Str
184
185The base for our bid, defaults to /var/run/$progname
186
187=item pidfile Str
188
189The file we store our PID in, defaults to /var/run/$progname/
190
191=item foreground Bool
192
193If true, the process won't background. Useful for debugging. This option can be set via Getopt's -f.
194
195=back
196
197=head1 METHODS
198
199=over
200
201=item check()
202
203Check to see if an instance is already running.
204
205=item start()
206
207Setup a pidfile, fork, then setup the signal handlers.
208
209=item stop()
210
211Stop the process matching the pidfile, and unlinks the pidfile.
212
213=item restart()
214
215Litterally
216
217 $self->stop();
218 $self->start();
219
220=item daemonize()
221
222Calls C<Proc::Daemon::Init> to daemonize this process.
223
224=item kill($pid)
225
226Kills the process for $pid. This will try SIGINT, and SIGTERM before falling back to SIGKILL and finally giving up.
227
228=item setup_signals()
229
230Setup the signal handlers, by default it only sets up handlers for SIGINT and SIGHUP
231
232=item handle_sigint()
233
234Handle a INT signal, by default calls C<$self->stop()>;
235
236=item handle_sighup()
237
238Handle a HUP signal. Nothing is done by default.
239
240=item meta()
241
242the C<meta()> method from L<Class::MOP::Class>
243
244=back
245
246=head1 DEPENDENCIES
247
248=for author to fill in:
249 A list of all the other modules that this module relies upon,
250 including any restrictions on versions, and an indication whether
251 the module is part of the standard Perl distribution, part of the
252 module's distribution, or must be installed separately. ]
253
254Obviously L<Moose>, also L<Carp>, L<Proc::Daemon>, L<File::Flock>, L<File::Slurp>
255
256=head1 INCOMPATIBILITIES
257
258=for author to fill in:
259 A list of any modules that this module cannot be used in conjunction
260 with. This may be due to name conflicts in the interface, or
261 competition for system or program resources, or due to internal
262 limitations of Perl (for example, many modules that use source code
263 filters are mutually incompatible).
264
265None reported.
266
267
268=head1 BUGS AND LIMITATIONS
269
270=for author to fill in:
271 A list of known problems with the module, together with some
272 indication Whether they are likely to be fixed in an upcoming
273 release. Also a list of restrictions on the features the module
274 does provide: data types that cannot be handled, performance issues
275 and the circumstances in which they may arise, practical
276 limitations on the size of data sets, special cases that are not
277 (yet) handled, etc.
278
279No bugs have been reported.
280
281Please report any bugs or feature requests to
282C<bug-acme-dahut-call@rt.cpan.org>, or through the web interface at
283L<http://rt.cpan.org>.
284
285=head1 SEE ALSO
286
287L<Proc::Daemon>, L<Daemon::Generic>, L<MooseX::Getopt>
288
289=head1 AUTHOR
290
291Chris Prather C<< <perigrin@cpan.org> >>
292
293
294=head1 LICENCE AND COPYRIGHT
295
296Copyright (c) 2007, Chris Prather C<< <perigrin@cpan.org> >>. All rights reserved.
297
298This module is free software; you can redistribute it and/or
299modify it under the same terms as Perl itself. See L<perlartistic>.
300
301
302=head1 DISCLAIMER OF WARRANTY
303
304BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
305FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
306OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
307PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
308EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
309WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
310ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
311YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
312NECESSARY SERVICING, REPAIR, OR CORRECTION.
313
314IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
315WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
316REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
317LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
318OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
319THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
320RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
321FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
322SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
323SUCH DAMAGES.