Jump to content

Protecting PHP from hung CLI calls


l008com

Recommended Posts

I have a script that runs periodically by a launchd timer. I give the script a very tight timeout ( set_time_limit(120); ). 

Most of the time, my script works great. But every once in a while, one of the commands I run in an exec( ) call seems to hang. This of course is a problem because once the exec( ) call hangs, the php script hangs as time spent on exec( ) calls does not count towards the script's runtime. 

Furthermore since the script is still running, launchd doesn't call it again. So in this way, my script is entirely at the mercy of a command line program not having a problem. And if it does, I can't do anything about it.  

So while I could try to figure out why my particular command seems to go awry (which is its own weird issue), the bigger issue is how can I call command line programs in php in a way that don't allow a runaway command to lock up the whole script forever? I wish there was an exec( )-type function with timeout built in. Or even a script timelimit function that DID count pauses and external programs. Something to kill this!? Something other than a SECOND php script that would check on the first script and kill it when there is a problem. There MUST be a better solution than that?

Any thoughts?

Link to comment
Share on other sites

The timeout command would be the easiest way to handle this probably.  I didn't know that was a thing, good to know.

If for some reason that wasn't an option, you should be able to use proc_open and proc_terminate to accomplish the same task.  I don't have time ATM to try it and provide an example.  If I do later I may post an example.

Edited by kicken
Link to comment
Share on other sites

1 hour ago, kicken said:

If for some reason that wasn't an option, you should be able to use proc_open and proc_terminate to accomplish the same task.  I don't have time ATM to try it and provide an example.  If I do later I may post an example.

It gives more control, but one feature it doesn't have is a way to wait for the process to close or a timeout to expire. So unless I missed something, that means having to poll the process every couple seconds to see if it's still going, then giving up and terminating it if the 120s has passed.

Link to comment
Share on other sites

15 hours ago, requinix said:

So unless I missed something,

Nope, polling the process status is what I was speaking of.   With proc_open such a thing is possible where as with exec you're just stuck until the process is done.   Polling for the status isn't an ideal solution, but it's a solution if that timeout command isn't available (ie, on windows).

function run_with_timeout($cmd, $timeout = 30){
    $handle = proc_open($cmd, [['pipe', 'r'], STDOUT, STDERR], $pipes);
    if (!$handle){
        throw new \RuntimeException('Unable to launch process');
    }

    fclose($pipes[0]);
    $start = time();

    try {
        do {
            usleep(500 * 1000);
            $status = proc_get_status($handle);
        } while ($status['running'] && time() - $start < $timeout);

        if ($status['running']){
            proc_terminate($handle);
            throw new \RuntimeException('Timeout');
        }

        return $status['exitcode'];
    } finally {
        proc_close($handle);
    }
}

 

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.