Search code examples
perlperl-ipc-run

How to tell when an IPC::Run job has finished


Is there a simple, reliable way to tell when an IPC::Run task has completed, i.e. any child process(es) have exited?

The docs are astonishingly silent on this.

It seems that looping on pumpable works, though it's not really documented clearly as the right way to do things:

use strict;
use warnings;
use IPC::Run;
use 5.12.0;

my $handle = IPC::Run::start(['sleep', '10']);

while ($handle->pumpable)
{
    sleep(0.5);
    # do other stuff in the event loop
    # so we don't want to block on finish
}

$handle->finish;

print("exited with '" . $handle->result . "'");

Is there a better option? finish blocks, but then you can't do other work in your event loop while you wait for the proc to finish.

I'm surprised there isn't a simple

$handle->running

or

$handle->finished

Am I missing something obvious?

Similarly, there doesn't seem to be a documented way to get the pid of the child(ren).


Solution

  • I have not been able to find a clean way to do either, only other ways.

    Information about whether children are running can be obtained by result related methods, and by pumpable (what is already used in the question).

    The result method "Throws an exception if an out-of-range child number is passed". This happens if we query when no kids exited yet. So, with a single child process

    sub only_kid_finished { eval { $_[0]->result }; return $@ ? 0 : 1 }
    

    Better yet, results method returns a list of child exit values while it also "Throws an exception if the harness is not in a finished state". So it can be used the same way but with more kids it can also be used to keep track of how many exited/are left.

    As used in the question, pumpable can also inform whether any processes are running

    sub any_kids_left { return $_[0]->pumpable }
    

    It relates to I/O channels or processes, but if anything is running it must return true, otherwise false.

    The question of children PID is a bit vexing for me, since it is information that one may need to know. While it is right in the object, $handle->{KIDS}[0]{PID} (for first kid), I don't see how to retrieve it in a reasonable way. I'd think that a structure this basic can't change, so it would tempt me to actually use it, with checks. (Then I'd also be content with whatever I may get for poking at a class's internals, having deserved it.)

    Once PID is retrieved one can check up on the process with kill 0, $pid. Note that this returns true (1) until the process has been reaped (even when it exited but is a zombie).