[sf-perl] parallelize system tasks, collecting statuses and output

David Alban extasia at extasia.org
Fri Mar 14 19:38:47 PDT 2008


greetings,

our sysadmins regularly need to restart a service on, say thirty
machines.  the service takes two and a half minutes to restart.  i'd
like to write a perl program they can use to parallelize the restart.
so that the whole operation takes three minutes rather than an hour or
more.  i want to collect the statuses and any output of the service
restart commands.

i found the Bidirectional Communication with Yourself section of the
perlipc man page.  i'm trying to hack their example so that only the
child writer writes to the parent reader.  my hacked version forks two
child processes, which i want to run in parallel.  each child process
ssh's to a host, sleeps a small amount of time, and then runs the
hostname command.  but the child procs seem to be running serially.

#!/usr/bin/perl

use warnings;
use strict;

     # log_timestamp() below comes from this module
use <LOCAL LOGGING MODULE>;

use IO::Handle;

my @hosts = qw( hostname_1 hostname_2 );
my $numprocs = @hosts;

my @output;

for my $instance ( 1..$numprocs ) {
  my $index = $instance - 1;

  pipe( CHILD_READER, PARENT_WRITER )
    or die "can't pipe( CHILD_READER, PARENT_WRITER ): $!\n";

  PARENT_WRITER->autoflush( 1 );

  my $pid;

       # parent
  if ( $pid = fork() ) {
    close PARENT_WRITER;

    chomp( my $line = <CHILD_READER> );
    $output[ $index ] = $line;

    close CHILD_READER;
  } # if

       # child
  else {
    not defined $pid and die "can't fork: $!\n";

    close CHILD_READER;

    my $host = $hosts[ $index ];
    my @results = qx{ ssh $host "sleep 5; hostname" };

    print PARENT_WRITER
          log_timestamp(),
          " child pid $$; instance $instance; results => ",
          join( '', @results );

    close PARENT_WRITER;

    exit;
  } # if
} # for

for my $instance ( 1..$numprocs ) {
  my $index = $instance - 1;
  print $output[ $index ], "\n";
} # if



--------------------------------------------------------------------------------

i execute this as:

  $ date; perl junk; date


and get:

  Sat Mar 15 02:30:22 UTC 2008
  2008-03-15 02:30:27 +0000 child pid 5469; instance 1; results => hostname_1
  2008-03-15 02:30:32 +0000 child pid 5471; instance 2; results => hostname_2
  Sat Mar 15 02:30:32 UTC 2008


it's running the second child process only after the first one
finishes, which defeats my goal of parallelizing.  what am i missing?

there's so much stuff out there that promises to help with this and i
don't know whether i'm going down the wrong path.  surely you fine
folks must have done stuff like this before.  do indeed tell me to
rtfm, but please tell me which fm (or other doc) to r.

please also feel free to tell me i'm going about it totally the wrong
way, perhaps with a pointer in the general (better) direction.

thanks,
david
-- 
Live in a world of your own, but always welcome visitors.


More information about the SanFrancisco-pm mailing list