view release on metacpan or search on metacpan
meet all of these conditions:
a) You must cause the modified files to carry prominent notices stating that you
changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in whole or in
part contains or is derived from the Program or any part thereof, to be licensed
as a whole at no charge to all third parties under the terms of this License.
c) If the modified program normally reads commands interactively when run, you
must cause it, when started running for such interactive use in the most ordinary
way, to print or display an announcement including an appropriate copyright
notice and a notice that there is no warranty (or else, saying that you provide a
warranty) and that users may redistribute the program under these conditions,
and telling the user how to view a copy of this License. (Exception: if the
Program itself is interactive but does not normally print such an announcement,
your work based on the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If identifiable
sections of that work are not derived from the Program, and can be reasonably
considered independent and separate works in themselves, then this License,
eg/ghost_acme.pl view on Meta::CPAN
#!/usr/bin/perl -w
use strict;
my $g = MyGhost->new(
logfile => 'daemon.log',
pidfile => 'daemon.pid',
);
exit $g->ctrl(shift(@ARGV) // 'start'); # start, stop, restart, reload, status
1;
package MyGhost;
use parent 'Acme::Ghost';
sub init {
my $self = shift;
$SIG{HUP} = sub { $self->hangup }; # Listen USR2 (reload)
}
sub hangup {
my $self = shift;
$self->log->debug("Hang up!");
}
sub startup {
my $self = shift;
my $max = 100;
my $i = 0;
while ($self->ok) {
$i++;
sleep 3;
$self->log->debug(sprintf("> %d/%d", $i, $max));
last if $i >= $max;
}
}
eg/ghost_ae.pl view on Meta::CPAN
#!/usr/bin/perl -w
use strict;
my $g = MyGhost->new(
logfile => 'daemon.log',
pidfile => 'daemon.pid',
);
exit $g->ctrl(shift(@ARGV) // 'start', 0); # start, stop, restart, reload, status
1;
package MyGhost;
use parent 'Acme::Ghost';
use AnyEvent;
sub startup {
my $self = shift;
my $quit = AnyEvent->condvar;
my $i = 0;
# Create watcher timer
my $watcher = AnyEvent->timer (after => 1, interval => 1, cb => sub {
$quit->send unless $self->ok;
});
# Create process timer
eg/ghost_ioloop.pl view on Meta::CPAN
#!/usr/bin/perl -w
use strict;
my $g = MyGhost->new(
logfile => 'daemon.log',
pidfile => 'daemon.pid',
);
exit $g->ctrl(shift(@ARGV) // 'start', 0); # start, stop, restart, reload, status
1;
package MyGhost;
use parent 'Acme::Ghost';
use Mojo::IOLoop;
sub init {
my $self = shift;
$self->{loop} = Mojo::IOLoop->new;
}
sub startup {
my $self = shift;
my $loop = $self->{loop};
my $i = 0;
# Add a timers
my $timer = $loop->timer(5 => sub {
my $l = shift; # loop
$self->log->info("Timer!");
});
my $recur = $loop->recurring(1 => sub {
my $l = shift; # loop
$l->stop unless $self->ok;
$self->log->info("Tick! " . ++$i);
$l->stop if $i >= 10;
});
$self->log->debug("Start IOLoop");
# Start event loop if necessary
$loop->start unless $loop->is_running;
$self->log->debug("Finish IOLoop");
}
1;
__END__
eg/ghost_nobody.pl view on Meta::CPAN
#!/usr/bin/perl -w
use strict;
my $g = MyGhost->new(
pidfile => '/tmp/daemon.pid',
user => 'nobody',
group => 'nogroup',
);
exit $g->ctrl(shift(@ARGV) // 'start', 0); # start, stop, restart, status
1;
package MyGhost;
use parent 'Acme::Ghost';
sub startup {
my $self = shift;
my $max = 100;
my $i = 0;
while ($self->ok) {
$i++;
sleep 3;
$self->log->debug(sprintf("> %d/%d", $i, $max));
last if $i >= $max;
}
}
1;
__END__
sudo ACME_GHOST_DEBUG=1 perl -Ilib eg/ghost_nobody.pl start
eg/ghost_simple.pl view on Meta::CPAN
#!/usr/bin/perl -w
use strict;
use Acme::Ghost;
my $g = Acme::Ghost->new(
logfile => 'daemon.log',
pidfile => 'daemon.pid',
);
my $cmd = shift(@ARGV) // 'start';
if ($cmd eq 'status') {
if (my $runned = $g->status) {
print "Running $runned\n";
} else {
print "Not running\n";
}
exit 0; # Ok
} elsif ($cmd eq 'stop') {
if (my $runned = $g->stop) {
if ($runned < 0) {
print STDERR "Failed to stop " . $g->pid . "\n";
exit 1; # Error
}
print "Stopped $runned\n";
} else {
print "Not running\n";
}
exit 0; # Ok
} elsif ($cmd ne 'start') {
print STDERR "Command incorrect\n";
exit 1; # Error
}
# Daemonize
$g->daemonize;
my $max = 10;
my $i = 0;
while (1) {
eg/prefork_acme.pl view on Meta::CPAN
#!/usr/bin/perl -w
use strict;
my $g = MyGhost->new(
logfile => 'daemon.log',
pidfile => 'daemon.pid',
);
exit $g->ctrl(shift(@ARGV) // 'start');
1;
package MyGhost;
use parent 'Acme::Ghost::Prefork';
use Data::Dumper qw/Dumper/;
sub init {
my $self = shift;
eg/prefork_acme.pl view on Meta::CPAN
sleep 1;
$self->log->debug(sprintf("$$> %d/%d", $i, $max));
last if $i >= $max;
}
}
1;
__END__
perl -Ilib eg/prefork_acme.pl start
eg/prefork_ioloop.pl view on Meta::CPAN
#!/usr/bin/perl -w
use strict;
my $g = MyGhost->new(
logfile => 'daemon.log',
pidfile => 'daemon.pid',
);
exit $g->ctrl(shift(@ARGV) // 'start');
1;
package MyGhost;
use parent 'Acme::Ghost::Prefork';
use Mojo::IOLoop;
sub init {
my $self = shift;
eg/prefork_ioloop.pl view on Meta::CPAN
my $recur = $loop->recurring(1 => sub {
my $l = shift; # loop
$l->stop unless $self->tick;
$self->log->debug(sprintf("$$> %d/%d", ++$i, $max));
$l->stop if $i >= $max;
});
$self->log->debug("Start IOLoop");
# Start event loop if necessary
$loop->start unless $loop->is_running;
$self->log->debug("Finish IOLoop");
}
1;
__END__
perl -Ilib eg/prefork_ioloop.pl start
lib/Acme/Ghost.pm view on Meta::CPAN
List of LSB Daemon Control Methods
These methods can be used to control the daemon behavior.
Every effort has been made to have these methods DWIM (Do What I Mean),
so that you can focus on just writing the code for your daemon.
=head2 ctrl
exit $g->ctrl( shift @ARGV, 'USR2' );
# start, stop, restart, reload, status
Daemon Control Dispatcher with using USR2 to reloading
exit $g->ctrl( shift @ARGV, 0 );
This example shows how to forced suppress reloading (disable send users signals to daemon)
=head2 reload
$exit_code = $g->reload; # SIGHUP (by default)
$exit_code = $g->reload('USR2'); # SIGUSR2
$exit_code = $g->reload(12); # SIGUSR2 too
say "Reloading ". $g->pid;
This method performs sending signal to Your daemon and return C<0> as exit code.
This method is primarily intended to perform a daemon reload
=head2 restart
$exit_code = $g->restart;
if ($exit_code) {
say STDERR "Restart failed " . $g->pid;
} else {
say "Restart successful";
}
This method performs restarting the daemon and returns C<0> as successfully
exit code or C<1> in otherwise
=head2 start
my $exit_code = $g->start;
say "Running ". $g->pid;
exit $exit_code;
This method performs starting the daemon and returns C<0> as exit code.
The spawned process calls the startup handler and exits with status C<0>
as exit code without anything return
=head2 status
if (my $runned = $g->status) {
say "Running $runned";
} else {
say "Not running";
}
lib/Acme/Ghost.pm view on Meta::CPAN
=head2 init
sub init {
my $self = shift;
# . . .
}
The init() method is called after spawning (forking) and after daemonizing
=head2 startup
sub startup {
my $self = shift;
# . . .
}
The startup() method is called after daemonizing in service mode
This is your main hook into the service, it will be called at service startup.
Meant to be overloaded in a subclass.
=head2 cleanup
sub cleanup {
my $self = shift;
my $scope = shift; # 0 or 1
# . . .
}
lib/Acme/Ghost.pm view on Meta::CPAN
my $self = shift;
$self->log->debug(">> Hang up!");
}
=head1 EXAMPLES
=over 4
=item ghost_simple.pl
This is traditional way to start daemons
use Acme::Ghost;
my $g = Acme::Ghost->new(
logfile => 'daemon.log',
pidfile => 'daemon.pid',
);
my $cmd = shift(@ARGV) // 'start';
if ($cmd eq 'status') {
if (my $runned = $g->status) {
print "Running $runned\n";
} else {
print "Not running\n";
}
exit 0; # Ok
} elsif ($cmd eq 'stop') {
if (my $runned = $g->stop) {
if ($runned < 0) {
print STDERR "Failed to stop " . $g->pid . "\n";
exit 1; # Error
}
print "Stopped $runned\n";
} else {
print "Not running\n";
}
exit 0; # Ok
} elsif ($cmd ne 'start') {
print STDERR "Command incorrect\n";
exit 1; # Error
}
# Daemonize
$g->daemonize;
my $max = 10;
my $i = 0;
while (1) {
lib/Acme/Ghost.pm view on Meta::CPAN
=item ghost_acme.pl
Simple acme example of daemon with reloading demonstration
my $g = MyGhost->new(
logfile => 'daemon.log',
pidfile => 'daemon.pid',
);
exit $g->ctrl(shift(@ARGV) // 'start'); # start, stop, restart, reload, status
1;
package MyGhost;
use parent 'Acme::Ghost';
sub init {
my $self = shift;
$SIG{HUP} = sub { $self->hangup }; # Listen USR2 (reload)
}
sub hangup {
my $self = shift;
$self->log->debug("Hang up!");
}
sub startup {
my $self = shift;
my $max = 100;
my $i = 0;
while ($self->ok) {
$i++;
sleep 3;
$self->log->debug(sprintf("> %d/%d", $i, $max));
last if $i >= $max;
}
}
lib/Acme/Ghost.pm view on Meta::CPAN
=item ghost_ioloop.pl
L<Mojo::IOLoop> example
my $g = MyGhost->new(
logfile => 'daemon.log',
pidfile => 'daemon.pid',
);
exit $g->ctrl(shift(@ARGV) // 'start', 0); # start, stop, restart, reload, status
1;
package MyGhost;
use parent 'Acme::Ghost';
use Mojo::IOLoop;
sub init {
my $self = shift;
$self->{loop} = Mojo::IOLoop->new;
}
sub startup {
my $self = shift;
my $loop = $self->{loop};
my $i = 0;
# Add a timers
my $timer = $loop->timer(5 => sub {
my $l = shift; # loop
$self->log->info("Timer!");
});
my $recur = $loop->recurring(1 => sub {
my $l = shift; # loop
$l->stop unless $self->ok;
$self->log->info("Tick! " . ++$i);
$l->stop if $i >= 10;
});
$self->log->debug("Start IOLoop");
# Start event loop if necessary
$loop->start unless $loop->is_running;
$self->log->debug("Finish IOLoop");
}
1;
=item ghost_ae.pl
AnyEvent example
my $g = MyGhost->new(
logfile => 'daemon.log',
pidfile => 'daemon.pid',
);
exit $g->ctrl(shift(@ARGV) // 'start', 0); # start, stop, restart, reload, status
1;
package MyGhost;
use parent 'Acme::Ghost';
use AnyEvent;
sub startup {
my $self = shift;
my $quit = AnyEvent->condvar;
my $i = 0;
# Create watcher timer
my $watcher = AnyEvent->timer (after => 1, interval => 1, cb => sub {
$quit->send unless $self->ok;
});
# Create process timer
lib/Acme/Ghost.pm view on Meta::CPAN
$self->log->debug("Start AnyEvent");
$quit->recv; # Run!
$self->log->debug("Finish AnyEvent");
}
1;
=item ghost_nobody.pl
This example shows how to start daemons over nobody user and logging to syslog (default)
my $g = MyGhost->new(
pidfile => '/tmp/daemon.pid',
user => 'nobody',
group => 'nogroup',
);
exit $g->ctrl(shift(@ARGV) // 'start', 0); # start, stop, restart, status
1;
package MyGhost;
use parent 'Acme::Ghost';
sub startup {
my $self = shift;
my $max = 100;
my $i = 0;
while ($self->ok) {
$i++;
sleep 3;
$self->log->debug(sprintf("> %d/%d", $i, $max));
last if $i >= $max;
}
}
lib/Acme/Ghost.pm view on Meta::CPAN
use POSIX qw/ :sys_wait_h SIGINT SIGTERM SIGQUIT SIGKILL SIGHUP SIG_BLOCK SIG_UNBLOCK /;
use Acme::Ghost::FilePid;
use Acme::Ghost::Log;
use constant {
DEBUG => $ENV{ACME_GHOST_DEBUG} || 0,
IS_ROOT => (($> == 0) || ($< == 0)) ? 1 : 0,
SLEEP => 60,
INT_TRIES => 3,
LSB_COMMANDS=> [qw/start stop reload restart status/],
};
sub new {
my $class = shift;
my $args = @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {};
my $name = $args->{name} || File::Basename::basename($0);
my $user = $args->{user} // '';
my $group = $args->{group} // '';
# Get UID by User
lib/Acme/Ghost.pm view on Meta::CPAN
# Child
$self->{daemonized} = 1; # Set daemonized flag
$self->filepid->pid($$)->save; # Set new PID and Write PID file
chown($uid, $gid, $pid_file) if IS_ROOT && -e $pid_file;
# Set GID and UID
$self->set_gid->set_uid;
# Turn process into session leader, and ensure no controlling terminal
unless (DEBUG) {
die "Can't start a new session: $!" if POSIX::setsid() < 0;
}
# Init logger!
my $log = $self->log;
# Close all standart filehandles
unless (DEBUG) {
my $devnull = File::Spec->devnull;
open STDIN, '<', $devnull or die "Can't open STDIN from $devnull: $!\n";
open STDOUT, '>', $devnull or die "Can't open STDOUT to $devnull: $!\n";
lib/Acme/Ghost.pm view on Meta::CPAN
return $self;
}
sub is_daemonized { shift->{daemonized} }
sub is_spirited { shift->{spirited} }
sub pid { shift->{pid} }
# Hooks
sub preinit { }
sub init { }
sub cleanup { } # 0 -- at destroy; 1 -- at interrupt
sub startup { }
sub hangup { }
# Process
sub flush { # Flush process counters
my $self = shift;
$self->{interrupt} = 0;
$self->{signo} = 0;
$self->{ok} = 1;
return $self;
}
lib/Acme/Ghost.pm view on Meta::CPAN
$self->log->debug(sprintf("Request for terminate of ghost process %s received on signal %s", $self->pid, $signo));
if ($self->{interrupt} >= INT_TRIES) { # Forced terminate
POSIX::_exit(1) if $self->is_spirited;
$self->cleanup(1);
$self->log->fatal(sprintf("Ghost process %s forcefully terminated on signal %s", $self->pid, $signo));
$self->filepid->remove;
POSIX::_exit(1);
}
$self->{interrupt}++;
}
sub start {
my $self = shift;
$self->daemonize(1); # First daemonize and switch to child process
return 0 unless $self->is_daemonized; # Exit from parent process
# Signals Trapping for interruption
local $SIG{INT} = sub { $self->_term(SIGINT) }; # 2
local $SIG{TERM} = sub { $self->_term(SIGTERM) }; # 15
local $SIG{QUIT} = sub { $self->_term(SIGQUIT) }; # 3
$self->flush; # Flush process counters
$self->log->info(sprintf("Ghost process %s started", $self->pid));
$self->startup(); # Master hook
$self->log->info(sprintf("Ghost process %s stopped", $self->pid));
exit 0; # Exit code for child: ok
}
sub stop {
my $self = shift;
my $pid = $self->filepid->running;
$self->{pid} = $pid;
return 0 unless $pid; # Not running
# Try SIGQUIT ... 2s ... SIGTERM ... 4s ... SIGINT ... 3s ... SIGKILL ... 3s ... UNDEAD!
lib/Acme/Ghost.pm view on Meta::CPAN
return $pid;
}
# The ghost process doesn't seem to want to die. It is still running...;
return -1 * $pid;
}
sub status {
my $self = shift;
return $self->{pid} = $self->filepid->running || 0;
}
sub restart {
my $self = shift;
my $runned = $self->stop;
return 1 if $runned && $runned < 0; # It is still running
_sleep(1); # delay before starting
$self->start;
}
sub reload {
my $self = shift;
my $signo = shift // SIGHUP;
$self->{pid} = $self->filepid->running || 0;
return $self->start unless $self->pid; # Not running - start!
kill $signo, $self->pid;
return 0;
}
sub ctrl { # Dispatching
my $self = shift;
my $cmd = shift || '';
my $sig = shift; # SIGHUP
unless (grep {$cmd eq $_} @{(LSB_COMMANDS)}) {
print STDERR "Command incorrect\n";
return 1;
}
my $exit_code = 0; # Ok
if ($cmd eq 'start') {
$exit_code = $self->start;
printf "Running %s\n", $self->pid;
} elsif ($cmd eq 'status') {
if (my $runned = $self->status) {
printf "Running %s\n", $runned;
} else {
print "Not running\n";
}
} elsif ($cmd eq 'stop') {
if (my $runned = $self->stop) {
if ($runned < 0) {
printf STDERR "The ghost process %s doesn't seem to want to die. It is still running...\n", $self->pid;
$exit_code = 1;
} else {
printf "Stopped %s\n", $runned;
}
} else {
print "Not running\n";
}
} elsif ($cmd eq 'restart') {
$exit_code = $self->restart;
if ($exit_code) {
printf STDERR "Restart failed %s\n", $self->pid;
} else {
print "Restart successful\n";
}
} elsif ($cmd eq 'reload') {
$exit_code = $self->reload($sig);
printf "Reloading %s\n", $self->pid;
}
return $exit_code;
}
sub DESTROY {
my $self = shift;
lib/Acme/Ghost/Prefork.pm view on Meta::CPAN
amount of time you expect any one operation to block the event loop
Defaults to C<50>
=head2 spare
spare => 2
Temporarily spawn up to this number of additional spirits if there is a need
This allows for new spirits to be started while old ones are still shutting down gracefully,
drastically reducing the performance cost of spirit restarts.
Defaults to C<2>
=head2 spirits, workers
spirits => 4
Number of spirit processes.
A good rule of thumb is two spirit processes per CPU core for applications that perform mostly
lib/Acme/Ghost/Prefork.pm view on Meta::CPAN
This method is called immediately after creating the instance and returns it
B<NOTE:> Internal use only!
=head2 healthy
my $healthy = $g->healthy;
This method returns the number of currently active live spirit processes (with a heartbeat)
=head2 startup
$prefork->startup;
This method starts preforked process (manager and spirits) and wait for L</"MANAGER SIGNALS">
=head2 tick
my $ok = $g->tick;
my $ok = $g->tick(1); # marks the finished status
This is B<required> method of spirit main process that sends heartbeat message to
process manager and returns the status of the running server via the 'ok' attribute
=head1 MANAGER SIGNALS
lib/Acme/Ghost/Prefork.pm view on Meta::CPAN
my $self = shift;
my $pid = shift;
# . . .
}
Is called when a spirit process is spawned
sub spawn {
my $self = shift;
my $pid = shift;
$self->log->debug("Spirit $pid started");
}
=head2 waitup
sub waitup {
my $self = shift;
# . . .
}
Is called when the manager starts waiting for new heartbeat messages
sub waitup {
my $self = shift;
my $spirits = $prefork->{spirits};
$self->log->debug("Waiting for heartbeat messages from $spirits spirits");
}
=head2 spirit
B<The spirit body>
This hook is called when the spirit process has started and is ready to run in isolation.
This is main hook that MUST BE implement to in user subclass
sub spirit {
my $self = shift;
# . . .
}
=head1 EXAMPLES
=over 4
=item prefork_acme.pl
Prefork acme example of daemon with reloading demonstration
my $g = MyGhost->new(
logfile => 'daemon.log',
pidfile => 'daemon.pid',
);
exit $g->ctrl(shift(@ARGV) // 'start');
1;
package MyGhost;
use parent 'Acme::Ghost::Prefork';
use Data::Dumper qw/Dumper/;
sub init {
my $self = shift;
lib/Acme/Ghost/Prefork.pm view on Meta::CPAN
1;
=item prefork_ioloop.pl
L<Mojo::IOLoop> example
my $g = MyGhost->new(
logfile => 'daemon.log',
pidfile => 'daemon.pid',
);
exit $g->ctrl(shift(@ARGV) // 'start');
1;
package MyGhost;
use parent 'Acme::Ghost::Prefork';
use Mojo::IOLoop;
use Data::Dumper qw/Dumper/;
sub init {
lib/Acme/Ghost/Prefork.pm view on Meta::CPAN
my $recur = $loop->recurring(1 => sub {
my $l = shift; # loop
$l->stop unless $self->tick;
$self->log->debug(sprintf("$$> %d/%d", ++$i, $max));
$l->stop if $i >= $max;
});
$self->log->debug("Start IOLoop");
# Start event loop if necessary
$loop->start unless $loop->is_running;
$self->log->debug("Finish IOLoop");
}
1;
=back
=head1 TO DO
lib/Acme/Ghost/Prefork.pm view on Meta::CPAN
$self->{writer} = undef; # Writable pipe to send messages to manager
$self->{spare} = $args{spare} || SPARE;
$self->{spirits} = $args{spirits} || $args{workers} || SPIRITS;
$self->{heartbeat_interval} = $args{heartbeat_interval} || HEARTBEAT_INTERVAL;
$self->{heartbeat_timeout} = $args{heartbeat_timeout} || HEARTBEAT_TIMEOUT;
$self->{graceful_timeout} = $args{graceful_timeout} || GRACEFUL_TIMEOUT;
$self->{spirit_cb} = $args{spirit};
return $self;
}
sub startup {
my $self = shift;
# Pipe for spirit communication
pipe($self->{reader}, $self->{writer}) or croak("Can't create pipe: $!\n");
# Set manager signals
local $SIG{INT} = local $SIG{TERM} = sub { $self->_stop };
local $SIG{QUIT} = sub { $self->_stop(1) };
local $SIG{CHLD} = sub { while ((my $pid = waitpid -1, WNOHANG) > 0) { $self->_stopped($pid) } };
local $SIG{TTIN} = sub { $self->_increase };
local $SIG{TTOU} = sub { $self->_decrease };
# Starting
$self->log->info("Manager $$ started");
$self->{running} = 1;
$self->_manage while $self->{running};
$self->log->info("Manager $$ stopped");
}
sub healthy {
return scalar grep { $_->{healthy} } values %{shift->{pool}};
}
sub tick { # Spirit level
my $self = shift;
my $finished = shift || 0; # 0 - no finished; 1 - finished
$self->_heartbeat($finished);
return $self->ok;
}
# User hooks
sub finish { } # Emitted when the server shuts down
sub heartbeat { } # Emitted when a heartbeat message has been received from a spirit
sub reap { } # Emitted when a child process exited
sub spawn { } # Emitted when a spirit process is spawned
sub waitup { } # Emitted when the manager starts waiting for new heartbeat messages
sub spirit {
my $self = shift;
my $cb = $self->{spirit_cb};
return unless $cb;
return $self->$cb if ref($cb) eq 'CODE';
$self->log->error("Callback `spirit` is incorrect");
$self->tick(1);
}
# Internal methods
lib/Acme/Ghost/Prefork.pm view on Meta::CPAN
my $interval = $self->{heartbeat_interval};
my $hb_to = $self->{heartbeat_timeout};
my $gf_to = $self->{graceful_timeout};
my $now = Time::HiRes::time;
my $log = $self->log;
for my $pid (keys %{$self->{pool}}) {
next unless my $w = $self->{pool}{$pid}; # Get spirit struct
# No heartbeat (graceful stop)
if (!$w->{graceful} && ($w->{time} + $interval + $hb_to <= $now)) {
$log->error("Spirit $pid has no heartbeat ($hb_to seconds), restarting");
$w->{graceful} = $now;
}
# Graceful stop with timeout
my $graceful = $w->{graceful} ||= $self->{gracefully_stop} ? $now : undef;
if ($graceful && !$w->{attempt}) {
$w->{attempt}++;
$log->info("Stopping spirit $pid gracefully ($gf_to seconds)");
kill 'QUIT', $pid or $self->_stopped($pid);
}
lib/Acme/Ghost/Prefork.pm view on Meta::CPAN
$self->log->warn("Spirit $$ received QUIT signal") if DEBUG;
$self->_heartbeat(1); # Send finish command to manager
};
# Close reader pipe
delete $self->{reader};
# Reset the random number seed for spirit
srand;
$self->log->info("Spirit $$ started");
# Start spirit
$self->spirit;
exit 0; # EXIT FROM APPLICATION
}
sub _wait { # Manager level
my $self = shift;
# Call waitup hook