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

I have a script that spawns some children. They all take quite a while to run, creating directories and files along the way. I often notice things I'd like to change before the children die of natural causes, so then I have to shut everything down (which involves a few `grep` and `kill` calls) and delete any files the children created. It's not really a big deal, but a bit of a pain in the neck. I'd like to create a setup where the children are all monitored so when I start up the parent again, old children still running are reported.

My best idea so far is keeping a log file of children I've run with their PIDs, checking it and updating it every time the parent starts up. Kill and report any children still running, and die to let the user clean up directories and files by hand before a fresh run.

So my first question is this: Do any of you experts out there have a nicer solution than what I described?

Second, if this is a good way to go about it, what would be my best bet for adding children to the log file? Is there a way to set up a trigger which could automatically take care of it, or am I stuck having to remember to do it any place in the code where a new process starts up?

  • Comment on Keeping track of children from previous runs of a script

Replies are listed 'Best First'.
Re: Keeping track of children from previous runs of a script
by salva (Canon) on Mar 10, 2011 at 17:28 UTC
    Several options:
    • Make the children create files containing their PID in some directory when they start and remove them when they exit. The problem with this approach is that children may exit without cleaning up its pid file and another unrelated process may take the same PID before you restart the main one (though most OSs try to avoid reusing pids as much as possible)
    • Capture signals on the parent and make it kill the children before exiting. The problem here is that not all signals can be trapped.
    • Monitor the PID of the parent process (getppid) on the children and abort when it becomes 1.
      I think salva's first option is the best way to go. If you are really paranoid about PID-wrap, you could put the executable name in the file along with the PID. Then, if you determine that the PID is active, you can use a variety of methods to determine the executable name and match that as well.

      fnord

        ajwood, note also that the methods described in my post are not mutually exclusive. Actually, it is quite common to combine the first two.
      To avoid the problem of processes exiting before cleaning up, one could do the following: after the child has created its PID file, the child should lock the PID file. The lock will be gone as soon as the process exits - no matter what the reason of exiting is (well, I'm assuming a UNIX OS, I've no idea how other OSses work). To check whether a previous child is still running, open the PID files, and try to get a lock. If you can get a lock, the process is no longer running. Only if the file exists, and it's still locked, the process is still running.

      It also solves the problem of PID reuse.

Re: Keeping track of children from previous runs of a script
by atcroft (Abbot) on Mar 10, 2011 at 17:14 UTC

    My first thought in reading this was to use a database for maintaining the information, and functions so the additions would be consistent, but the additions to your code small.

    Hope that helps. (I look forward to the responses to this thread as well. :)

Re: Keeping track of children from previous runs of a script
by anonymized user 468275 (Curate) on Mar 10, 2011 at 17:48 UTC
    It seems to me that Parallel::ForkManager has a method of each of your requirements. For example, it can wait for all children and it can kill them. The fork has to be done by the pm->start method instead of the direct fork command. To generalise your usage where you repeatedly want to do the same thing for a fork management method, you could create a wrapper class that has your standard pre and post-method-call requirements in the wrapper method before and/or after the call to the pfm method.

    One world, one people