NAME
Acme::Ghost::Prefork - Pre-forking ghost daemon
SYNOPSIS
use Acme::Ghost::Prefork;
my $g = Acme::Ghost::Prefork->new(
logfile => '/tmp/daemon.log',
pidfile => '/tmp/daemon.pid',
spirit => sub {
my $self = shift;
my $max = 10;
my $i = 0;
while ($self->tick) {
$i++;
sleep 1;
$self->log->debug(sprintf("$$> %d/%d", $i, $max));
last if $i >= $max;
}
},
);
exit $g->ctrl(shift(@ARGV) // '');
DESCRIPTION
Pre-forking ghost daemon (server)
ATTRIBUTES
This class inherits all attributes from Acme::Ghost and implements the following new ones
graceful_timeout
graceful_timeout => 120
The maximum amount of time in seconds stopping a spirit gracefully may take before being forced to stop
Note that this value should usually be a little larger than the maximum amount of time you expect any one request to take
Defaults to 120
heartbeat_interval
heartbeat_interval => 5
Heartbeat interval in seconds, defaults to 5
heartbeat_timeout
heartbeat_timeout => 50
Maximum amount of time in seconds before a spirit without a heartbeat will be stopped gracefully
Note that this value should usually be a little larger than the maximum amount of time you expect any one operation to block the event loop
Defaults to 50
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 2
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 non-blocking operations. Blocking operations often require more amount of spirits and benefit from decreasing concurrency (often as low as 1
)
Defaults to 4
METHODS
This class inherits all methods from Acme::Ghost and implements the following new ones
again
This method is called immediately after creating the instance and returns it
NOTE: Internal use only!
healthy
my $healthy = $g->healthy;
This method returns the number of currently active live spirit processes (with a heartbeat)
startup
$prefork->startup;
This method starts preforked process (manager and spirits) and wait for "MANAGER SIGNALS"
tick
my $ok = $g->tick;
my $ok = $g->tick(1); # marks the finished status
This is 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
MANAGER SIGNALS
The manager process can be controlled at runtime with the following signals
INT, TERM
Shut down server immediately
QUIT
Shut down server gracefully
TTIN
Increase spirit pool by one
TTOU
Decrease spirit pool by one
SPIRIT SIGNALS
The spirit processes can be controlled at runtime with the following signals
QUIT
Stop spirit gracefully
HOOKS
This class inherits all hooks from Acme::Ghost and implements the following new ones
Any of the following methods may be implemented (overwriting) in your class
finish
sub finish {
my $self = shift;
my $graceful = shift;
# . . .
}
Is called when the server shuts down
sub finish {
my $self = shift;
my $graceful = shift;
$self->log->debug($graceful ? 'Graceful server shutdown' : 'Server shutdown');
}
heartbeat
sub heartbeat {
my $self = shift;
my $pid = shift;
# . . .
}
Is called when a heartbeat message has been received from a spirit
sub heartbeat {
my $self = shift;
my $pid = shift;
$self->log->debug("Spirit $pid has a heartbeat");
}
reap
sub reap {
my $self = shift;
my $pid = shift;
# . . .
}
Is called when a child process (spirit) finished
sub reap {
my $self = shift;
my $pid = shift;
$self->log->debug("Spirit $pid stopped");
}
spawn
sub spawn {
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");
}
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");
}
spirit
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;
# . . .
}
EXAMPLES
- 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; $SIG{HUP} = sub { $self->hangup }; } sub hangup { my $self = shift; $self->log->debug(Dumper($self->{pool})); } sub spirit { my $self = shift; my $max = 10; my $i = 0; while ($self->tick) { $i++; sleep 1; $self->log->debug(sprintf("$$> %d/%d", $i, $max)); last if $i >= $max; } } 1;
- prefork_ioloop.pl
-
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 { my $self = shift; $self->{loop} = Mojo::IOLoop->new; } sub spirit { my $self = shift; my $loop = $self->{loop}; my $max = 10; 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->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;
TO DO
See TODO
file
SEE ALSO
Acme::Ghost, Mojo::Server::Prefork
AUTHOR
Serż Minus (Sergey Lepenkov) https://www.serzik.com <abalama@cpan.org>
COPYRIGHT
Copyright (C) 1998-2024 D&D Corporation. All Rights Reserved
LICENSE
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
See LICENSE
file and https://dev.perl.org/licenses/