Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 167 lines (129 sloc) 4.182 kb
#!/usr/bin/perl
#
# Dreamwidth worker manager
#
# Written by Mark Smith <mark@dwscoalition.org>.
#
# This maintains a group of workers for ESN and the like. It can manage any
# process that can be run and needs to be restarted if it dies. Configuration
# is done from the $LJHOME/etc directory, workers.conf.
#
use strict;
use lib "$ENV{LJHOME}/extlib/lib/perl5";
use lib "$ENV{LJHOME}/cgi-bin";
BEGIN {
require 'ljlib.pl';
}
use POSIX qw/ :sys_wait_h /;
use YAML;
use LJ::Directories;
# daemonize ourselves unless debugging
my $debug = $ARGV[0] eq '--debug' ? 1 : 0;
daemonize() unless $debug;
# setup termination catcher
use sigtrap handler => \&terminate, qw/ INT ABRT QUIT TERM /;
# now get config
my $config_file;
my $want = load_config( \$config_file )
or die $config_file ? "no jobs configured in $config_file\n" : "could not find an etc/workers.conf file";
# main loop is pretty simple, reap and spawn
my ( %have, %kids );
while (1) {
reap_children( \%have, \%kids );
spawn_children( $want, \%have, \%kids );
sleep 5;
}
################################################################################
################################################################################
################################################################################
sub load_config {
print "load_config()\n" if $debug;
my $config_file_ref = $_[0];
my $fn = LJ::resolve_file( "etc/workers.conf" );
$$config_file_ref = $fn;
return unless -e $fn;
my $conf = YAML::LoadFile( $fn )
or die "Unable to read YAML formatted config: $fn\n";
my $hostname = `hostname`;
$hostname =~ s/^([^.]+)(?:\..+)?\r?\n$/$1/;
die "Unable to get current hostname\n"
unless $hostname;
my %jobs;
foreach my $job ( keys %{ $conf->{all} || {} }, keys %{ $conf->{$hostname} || {} } ) {
my ( $path, $ct ) = ( $job, $conf->{$hostname}->{$job} || $conf->{all}->{$job} );
my @fns = ( $path, "$ENV{LJHOME}/$path", "$ENV{LJHOME}/bin/worker/$path" );
foreach my $ffn ( @fns ) {
if ( -e $ffn ) {
print "\tconfigured $ct $ffn\n" if $debug;
$jobs{$ffn} = $ct;
last;
}
}
}
return \%jobs;
}
sub daemonize {
my ( $pid, $sess_id, $i );
## Fork and exit parent
if ($pid = fork) { exit 0; }
## Detach ourselves from the terminal
die "Cannot detach from controlling terminal"
unless $sess_id = POSIX::setsid();
## Prevent possibility of acquiring a controling terminal
$SIG{'HUP'} = 'IGNORE';
if ($pid = fork) { exit 0; }
## Change working directory
chdir "/";
## Clear file creation mask
umask 0;
## Close open file descriptors
close(STDIN);
close(STDOUT);
close(STDERR);
## Reopen stderr, stdout, stdin to /dev/null
open(STDIN, "+>/dev/null");
open(STDOUT, "+>&STDIN");
open(STDERR, "+>&STDIN");
}
sub start_worker {
my $cmd = shift;
print "start_worker( $cmd )\n" if $debug;
my $pid = fork;
return $pid if $pid;
exec($cmd);
exit 0; # just in case exec fails
}
sub reap_children {
my ( $have, $kids ) = @_;
print "reap_children()\n" if $debug;
while ( ( my $pid = waitpid( -1, WNOHANG ) ) > 0 ) {
my $job = $kids->{$pid};
next unless $job && exists $have->{$job};
print "\treaped $pid $job\n";
delete $have->{$job}->{$pid};
delete $kids->{$pid};
}
}
sub spawn_children {
my ( $want, $have, $kids ) = @_;
print "spawn_children()\n" if $debug;
foreach my $job ( keys %$want ) {
my $ct = keys %{ $have->{$job} || {} };
next if $ct >= $want->{$job};
my $pid = start_worker( $job );
$have->{$job}->{$pid} = 1;
$kids->{$pid} = $job;
}
}
sub terminate {
print "terminate()\n" if $debug;
kill 15, $_ foreach keys %kids;
my $stop = time + 10;
while ( time < $stop && scalar(keys %kids) > 0 ) {
reap_children( \%have, \%kids );
select( undef, undef, undef, 0.25 );
}
kill 9, $_ foreach %kids;
# ensure we exit now :-)
exit 0;
}
Jump to Line
Something went wrong with that request. Please try again.