Skip to main content

set_time_limit is not effecting PHP-CLI



any solution to this ?







#!/usr/bin/php -q

<?php

set_time_limit(2);

sleep(5); // actually, exec() call that takes > 2 seconds

echo "it didn't work again";







Source: Tips4all

Comments

  1. The solution here is to use pcntl_fork(). I'm afraid it's POSIX only. PHP will need to be compiled with --enable-pcntl and not --disable-posix. Your code should look something like this:

    <?php

    function done($signo)
    {
    // You can do any on-success clean-up here.
    die('Success!');
    }

    $pid = pcntl_fork();
    if (-1 == $pid) {
    die('Failed! Unable to fork.');
    } elseif ($pid > 0) {
    pcntl_signal(SIGALRM, 'done');
    sleep($timeout);
    posix_kill($pid, SIGKILL);
    // You can do any on-failure clean-up here.
    die('Failed! Process timed out and was killed.');
    } else {
    // You can perform whatever time-limited operation you want here.
    exec($cmd);
    posix_kill(posix_getppid(), SIGALRM);
    }

    ?>


    Basically what this does is fork a new process which runs the else { ... } block. At the (successful) conclusion of that we send an alarm back to the parent process, which is running the elseif ($pid > 0) { ... } block. That block has a registered signal handler for the alarm signal (the done() callback) which terminates successfully. Until that is received, the parent process sleeps. When the timeout sleep() is complete, it sends a SIGKILL to the (presumably hung) child process.

    ReplyDelete
  2. The max_execution_time limit, which is what set_time_limit sets, counts (at least, on Linux) the time that is spent by the PHP process, while working.

    Quoting the manual's page of set_time_limit() :


    Note: The set_time_limit() function and the configuration
    directive max_execution_time only
    affect the execution time of the
    script itself. Any time spent on
    activity that happens outside the
    execution of the script such as system
    calls using system(), stream
    operations, database queries, etc. is
    not included when determining the
    maximum time that the script has been
    running. This is not true on
    Windows where the measured time is
    real.


    When, you are using sleep(), your PHP script is not working : it's just waiting... So the 5 seconds you are waiting are not being taken into account by the max_execution_time limit.

    ReplyDelete
  3. Could you try running your php via exec and use the "timeout" command? (http://packages.ubuntu.com/lucid/timeout)

    usage: timeout [-signal] time command.

    ReplyDelete
  4. I'm ssuming that the script hangs in a loop somewhoere. Why not simply do a $STARTUP_TIME=time() the the script start, and then keep checking in the loop if the script neeeds to exit?

    ReplyDelete
  5. Very hackish, but since I use cli scripts a lot, I admit shamefully to having slapped up a similar hack in the past. 2 scripts needed.

    Your first cron script (the one that hangs) logs its starttime and processid in a flat file -> the function getmypid will be your friend for this. A second script run from cron every (x) minutes checks the flatfile, kills whatever has passed the alloted execution time, clears the flatfile and even logs in another file if you want.

    Good luck ;)

    UPDATE:

    Remembered this question and came back to post this. While rummaging through Sebastian Bergmann's github account I stumbled on php-invoker. In the words of the author:



    Utility class for invoking PHP callables with a timeout.



    Although the current answer is very good for linux based non portable use, if cross-platform solution is needed this solution should be windows compatible, for those poor souls running on windoze. Mr Bergmann being a PHP god, I totally vouch for the quality of the script.

    ReplyDelete
  6. EDIT 1

    I noticed this comment in PHP manual:


    Please note that, under Linux,
    sleeping time is ignored, but under
    Windows, it counts as execution time.


    As far as what I understand, sleep is implemented as a system call and therefore ignored by PHP as described in the manual.

    EDIT 2


    there is an exec() running instead of
    sleep() there. and some exec() stuff
    hangs indefinitely. i am also
    searching for killing it from within
    exec (on linux shell), like
    exec(kill_after15secs myscript.sh),
    but i can't seem to find that either


    I now see the actual question. Assuming that you're working in a Lunix/Unix environment, you can devise a solution around these lines:

    <?php $pid = system( 'sh test.sh >test-out.txt 2>&1 & echo $!' ); ?>


    Guess what, this captured the process id of the process you started. You can log it into a database or text file along with timestamp. In another cron script that runs, say, every 5 minutes, retrieve all process ids that were created 5 minutes ago and check if they are still running:

    <?php $status = system( 'ps ' . $pid ); ?>


    If process is still running, you get two lines of output:

    PID TTY STAT TIME COMMAND
    2044 ? S 0:29 sh test.sh


    If so, terminate it like this:

    <?php system( 'kill ' . $pid ); ?>


    I wrote an article about creating background processes in PHP (and hunt them down afterwards). All examples were copied from there.

    EDIT 3

    All dots connected together:

    <?php
    $pid = system( 'sh test.sh >test-out.txt 2>&1 & echo $!' );
    $timer = 300;
    while( --$timer ) {
    sleep(1);
    $status = system( 'ps ' . $pid );
    $status = explode( "\n", $status, 2 ); // I am not sure, please experiment a bit here
    if ( count( $status ) == 1 || trim( $status[ 1 ] ) == '' ) {
    die( 'spawned process ended successfully' );
    }
    }
    system( 'kill ' . $pid );
    die( 'spawned process was terminated' );
    ?>

    ReplyDelete

Post a Comment

Popular posts from this blog

Why is this Javascript much *slower* than its jQuery equivalent?

I have a HTML list of about 500 items and a "filter" box above it. I started by using jQuery to filter the list when I typed a letter (timing code added later): $('#filter').keyup( function() { var jqStart = (new Date).getTime(); var search = $(this).val().toLowerCase(); var $list = $('ul.ablist > li'); $list.each( function() { if ( $(this).text().toLowerCase().indexOf(search) === -1 ) $(this).hide(); else $(this).show(); } ); console.log('Time: ' + ((new Date).getTime() - jqStart)); } ); However, there was a couple of seconds delay after typing each letter (particularly the first letter). So I thought it may be slightly quicker if I used plain Javascript (I read recently that jQuery's each function is particularly slow). Here's my JS equivalent: document.getElementById('filter').addEventListener( 'keyup', function () { var jsStart = (new Date).getTime()...

Is it possible to have IF statement in an Echo statement in PHP

Thanks in advance. I did look at the other questions/answers that were similar and didn't find exactly what I was looking for. I'm trying to do this, am I on the right path? echo " <div id='tabs-".$match."'> <textarea id='".$match."' name='".$match."'>". if ($COLUMN_NAME === $match) { echo $FIELD_WITH_COLUMN_NAME; } else { } ."</textarea> <script type='text/javascript'> CKEDITOR.replace( '".$match."' ); </script> </div>"; I am getting the following error message in the browser: Parse error: syntax error, unexpected T_IF Please let me know if this is the right way to go about nesting an IF statement inside an echo. Thank you.