walkingthecow has asked for the wisdom of the Perl Monks concerning the following question:

Basically, what I am trying to do is this: I have a timer that does a countdown from a specified time. I would like for that timer to do a countdown, while in the background a command is being run. As soon as the command gets the output that it needs, the timer is ended and the script resumes flow. Here's what I have:

# Countdown Timer sub sleep_count { my $minutes = shift; my $string = shift; my $command = shift; my $command_time_interval = shift; my $countdown = $minutes*60; # in secs. $| = 1; my $beg_time = time; my $end_time = $beg_time + $countdown; for (;;) { my $time = time; last if ($time >= $end_time); printf("\r[ %02d:%02d ] $string", ($end_time - $time) / ( 60) % 60, ($end_time - $time) % 60, ); sleep(1); } }
my $pid = fork(); if ($pid == 0) { sleep_count(3, 'Verifying with Nagios that resin is down: '); } else { my $nagios_check = `/usr/lib/nagios/plugins/check_http -H host.com + -I $ip -p 80`; until ( $nagios_check !~ /HTTP OK HTTP\/1.0 200 OK/ ) { $nagios_check = `/usr/lib/nagios/plugins/check_http -H host.co +m -I $ip -p 80`; sleep 10; } waitpid($pid,0); }
So basically what I am trying to do is check Nagios every 10 seconds for 3 minutes until the server is reported as down. While this check is going on there is a timer that reports how much time of the 3 minutes is left. As soon as Nagios returns that the server is down, the timer is stopped and script continues on.

I realize I am probably not on the right track, but any help is really appreciated. Thanks guys/girls!

Replies are listed 'Best First'.
Re: Having a difficult time understanding fork()
by crashtest (Curate) on Apr 07, 2010 at 02:19 UTC

    Based on the description of your requirement, it sounds like you will need to fork two children - one to check the server, one to do the countdown. Something like this:

    use strict; use warnings; use feature qw(:5.10); # Fork off two child processes my ($who_am_i, $countdown_pid, $checking_pid); $countdown_pid = fork(); if ($countdown_pid == 0){ $who_am_i = "countdown process"; } elsif ($countdown_pid){ $checking_pid = fork(); if ($checking_pid == 0){ $who_am_i = "checking process"; } elsif ($checking_pid){ $who_am_i = "controlling process"; } else{ die "Error forking: $!"; } } else{ die "Error forking: $!"; } # Each process does different things: given($who_am_i){ when ("countdown process"){ sleep_count(3, 'Verifying with Nagios that resin is down: '); } when ("checking process"){ # repeatedly do server check via "nagios" } when ("controlling process"){ # Wait on the "checking process" to complete. waitpid($checking_pid, 0); # Kill countdown timer kill("TERM", $countdown_pid); waitpid($countdown_pid, 0); } }

    You should probably check the exit status of your child processes (via $? after the waitpid calls).

    Hope this helps.

    Update: Actually, there's no need to have three processes. Two is enough, as in your post, although conceptually I like the idea of delegating each subtask to separate child processes.

    Perhaps the only piece that was really missing from your code was killing off the countdown timer.

Re: Having a difficult time understanding fork()
by 7stud (Deacon) on Apr 07, 2010 at 02:55 UTC

    I, on the other hand, don't understand why you are using fork() at all.

    use strict; use warnings; use 5.010; use List::Util qw{ shuffle }; my $interval = 2; #seconds my $total_time = 1; #minutes my $num_checks = ($total_time * 60) / $interval; my $start_time = time; my @status = ('up') x 9; push @status, 'down'; #1 in 10 chance server will be down $| = 1; MONITOR_STATUS_LOOP: for (1 .. $num_checks) { my $result = (shuffle @status)[0]; say $result; my $elapsed_time = time - $start_time; say "time left: ", $total_time * 60 - $elapsed_time, " seconds"; last MONITOR_STATUS_LOOP if $result eq 'down'; sleep $interval; } say "on with the rest of the script"; --output:-- up time left: 60 seconds up time left: 58 seconds up time left: 56 seconds down time left: 54 seconds on with the rest of the script