| Proc-Launcher documentation | Contained in the Proc-Launcher distribution. |
Proc::Launcher::Manager - manage multiple Proc::Launcher objects
version 0.0.35
use Proc::Launcher::Manager;
my $shared_config = { x => 1, y => 2 };
my $monitor = Proc::Launcher::Manager->new( app_name => 'MyApp' );
# a couple of different components
$monitor->register( daemon_name => 'component1',
start_method => sub { MyApp->start_component1( $config ) }
);
$monitor->register( daemon_name => 'component2',
start_method => sub { MyApp->start_component2( $config ) }
);
# using class/method/context rather than a code ref
$monitor->register( daemon_name => 'webui',
class => 'MyApp::WebUI',
start_method => 'start_webui',
context => $config,
);
# start all registered daemons. processes that are already
# running won't be restarted.
$monitor->start();
# stop all daemons
$monitor->stop();
sleep 1;
$monitor->force_stop();
# display all processes stdout/stderr from the log file that's
# been generated since we started
$monitor->read_log( sub { print "$_[0]\n" } );
# get a specific daemon or perform actions on one
my $webui = $monitor->daemon('webui');
$monitor->daemon('webui')->start();
# start the process supervisor. this will start up an event loop
# and won't exit until it is killed. any processes not already
# running will be started. all processes will be monitored and
# automatically restarted if they exit.
$monitor->supervisor->start();
# shut down/restart the supervisor
$monitor->supervisor->stop();
$monitor->supervisor->force_stop();
$monitor->supervisor->restart();
This library makes it easier to deal with multiple Proc::Launcher processes by providing methods to start and stop all daemons with a single command. Please see the documentation in Proc::Launcher to understand how this these libraries differ from other similar forking and controller modules.
It also provides a supervisor() method which will fork a daemon that will monitor the other daemons at regular intervals and restart any that have stopped. Note that only one supervisor can be running at any given time for each pid_dir.
There is no tracking of inter-service dependencies nor predictable ordering of service startup. Instead, daemons should be designed to wait for needed resources. See Launcher::Cascade if you need to handle dependencies.
Create a new Proc::Launcher object with the specified options. If the specified daemon already exists, no changes will be made.
Return the Proc::Launcher object for a specified daemon.
Return a list of Proc::Launcher objects.
Return a list of the names of all registered daemons.
Return a list of the names of daemons that are currently running.
This will begin by calling rm_zombies() on one of daemon objects, sleeping a second, and then calling rm_zombies() again. So far the test cases have always passed when using this strategy, and inconsistently passed with any subset thereof.
While it seems that this is more complicated than shutting down a single process, it's really just trying to be a bit more efficient. When managing a single process, is_running might be called a few times until the process exits. Since we might be managing a lot of daemons, this method is likely to be a bit more efficient and will hopefully only need to be called once (after the daemons have been given necessary time to shut down).
This may be reworked a bit in the future since calling sleep will halt all processes in single-threaded cooperative multitasking frameworks.
Call the start() method on all registered daemons. If the daemon is already running it will not be restarted.
Call the stop() method on all daemons.
Call the force_stop method on all daemons.
Call the disable() method on all daemons.
Call the enable() method on all daemons.
Poll all daemons for output for the specified number of seconds. Any output received in that time will be sent to $output_callback. Each line of output will be prefixed with the daemon name.
| Proc-Launcher documentation | Contained in the Proc-Launcher distribution. |
package Proc::Launcher::Manager; use strict; use warnings; our $VERSION = '0.0.35'; # VERSION use Mouse; use Carp; use File::Path; use POSIX qw(:sys_wait_h); use Proc::Launcher; use Proc::Launcher::Supervisor;
#_* Roles with 'Proc::Launcher::Roles::Launchable'; #_* Attributes has 'debug' => ( is => 'ro', isa => 'Bool', default => 0, ); has 'pid_dir' => ( is => 'ro', isa => 'Str', lazy => 1, default => sub { my $dir = join "/", $ENV{HOME}, "logs"; unless ( -d $dir ) { mkpath( $dir ); } return $dir; }, ); has 'launchers' => ( is => 'rw', isa => 'HashRef[Proc::Launcher]', ); has 'supervisor' => ( is => 'rw', lazy => 1, default => sub { my $self = shift; return Proc::Launcher->new( daemon_name => 'supervisor', pid_dir => $self->pid_dir, start_method => sub { Proc::Launcher::Supervisor->new( manager => $self )->monitor(); }, ); }, ); #_* Methods
sub register { my ( $self, %options ) = @_; $options{pid_dir} = $self->pid_dir; my $daemon; unless ( $self->{daemons}->{ $options{daemon_name} } ) { $daemon = Proc::Launcher->new( %options ); } # just capturing the position of the tail end of the log file $self->read_log( undef, $daemon ); $self->{daemons}->{ $options{daemon_name} } = $daemon; }
sub daemon { my ( $self, $daemon_name ) = @_; return $self->{daemons}->{ $daemon_name }; }
sub daemons { my ( $self ) = @_; my @daemons; for my $daemon_name ( $self->daemons_names() ) { push @daemons, $self->{daemons}->{ $daemon_name }; } return @daemons; }
sub daemons_names { my ( $self ) = @_; return ( sort keys %{ $self->{daemons} } ); }
sub is_running { my ( $self ) = @_; my @daemon_names = $self->daemons_names(); unless ( scalar @daemon_names ) { print "is_running() called when no daemons registered\n"; return; } # clean up deceased child processes before checking if processes # are running. $self->daemon($daemon_names[0])->rm_zombies(); # # give any processes that have ceased a second to shut down sleep 1; # again clean up deceased child processes before checking if # processes are running. $self->daemon($daemon_names[0])->rm_zombies(); my @running = (); for my $daemon_name ( @daemon_names ) { if ( $self->daemon($daemon_name)->is_running() ) { push @running, $daemon_name } } return @running; }
sub start { my ( $self, $data ) = @_; my $started; for my $daemon ( $self->daemons() ) { if ( $daemon->is_running() ) { print "daemon already running: ", $daemon->daemon_name, "\n"; } else { print "starting daemon: ", $daemon->daemon_name, "\n"; $daemon->start(); $started++; } } return $started; }
sub stop { my ( $self ) = @_; for my $daemon ( $self->daemons() ) { print "stopping daemon: ", $daemon->daemon_name, "\n"; $daemon->stop(); } return 1; }
sub force_stop { my ( $self ) = @_; for my $daemon ( $self->daemons() ) { print "forcefully stopping daemon: ", $daemon->daemon_name, "\n"; $daemon->force_stop(); } return 1; }
sub disable { my ( $self ) = @_; for my $daemon ( $self->daemons() ) { print "disabling daemon: ", $daemon->daemon_name, "\n"; $daemon->disable(); } return 1; }
sub enable { my ( $self ) = @_; for my $daemon ( $self->daemons() ) { print "enabling daemon: ", $daemon->daemon_name, "\n"; $daemon->enable(); } return 1; }
sub read_log { my ( $self, $output_callback, @daemons ) = @_; unless ( scalar @daemons ) { @daemons = $self->daemons() } for my $daemon ( @daemons ) { $daemon->read_log( $output_callback ); } }
sub tail { my ( $self, $output_callback, $timeout ) = @_; # create an array of Log::Tail objects to be passed to select() my @tails; # select() will return the paths associated with each daemon, so # we need to be able to look up the name of a daemon based on it's # log file path. my %daemons; for my $daemon ( $self->daemons() ) { push @tails, $daemon->file_tail; $daemons{ $daemon->log_file } = $daemon->daemon_name; } # calculate the time when we're done processing. my $end = time + $timeout; # display all new log output to stdout my $count; while ( 1 ) { my ($nfound,$timeleft,@pending)= File::Tail::select(undef,undef,undef,1,@tails); if ($nfound) { foreach (@pending) { my $daemon_name = $daemons{ $_->{input} } || $_->{input}; my $text = $_->read; for my $line ( split /\n/, $text ) { my $output = sprintf( "%-8s: %-1s", $daemon_name, $line ); $output_callback->( "$output\n" ); } } } else { # if we spawned any child procs, reap any that died waitpid(-1, WNOHANG); sleep 1; } # if timeout was specified, quit when the timeout has passed. if ( $timeout ) { last if time > $end; } } return 1; }
no Mouse; 1;