phpsleepwakeup

PHP, wake up process which is sleeping


I have two PHP scripts which are running at the same time. One of them (SleepingScript.php) calls the sleep function. The other script (WakeScript.php) should be able to wake up the sleeping script if necessary.

How can I achieve this?

Here is some code that explains better the situation.

SleepingScript.php

<?php
   $myPid = getmypid();
   /* save $myPid to database or file */
   sleep( 120 );
   /* other statements executed after 2 minutes or when woken up by WakeScript */
?>

WakeScript.php

<?php
    /* ... */
    if( $wakeUpNeeded ) {
      $pid = readSavedPid();
      wake( $pid );
    }
?>

Solution

  • This can be done using the process signal SIGCONT to inform the script it needs to wake up. Note that this requires the php extension pcntl and may be platform dependent (tested on macOS Big Sur):

    SleepingScript.php

    <?php
    
    if (!extension_loaded('pcntl')) {
        echo 'Unable to wake up!\n';
    } else {
        // While we aren't doing anything with the CONT signal, we need
        // it to be handled so that the process can wake up from sleep
        pcntl_signal(SIGCONT, function () {});
    }
    
    // Save this to file, redis, or something else
    echo posix_getpid() . "\n";
    
    // Sometimes time_nanosleep isn't available on your platform
    // If it's not, you'll need to substitute using sleep/usleep and maybe hrtime
    $seconds = 120;
    $nanoseconds = 0;
    $nano = time_nanosleep($seconds, $nanoseconds);
    
    if ($nano === true) {
        echo "Slept for $seconds seconds, $nanoseconds nanoseconds.\n";
    } elseif ($nano === false) {
        echo "Sleeping failed.\n";
    } else {
        echo "Interrupted by a signal.\n";
        echo "Time remaining: {$nano['seconds']} seconds, {$nano['nanoseconds']} nanoseconds.";
    }
    

    WakeScript.php

    <?php
    
    // Get saved pid. This could be from file, redis, or something else.
    // Here we're going to use the first argument for ease
    $pid = (int)$argv[1];
    
    // While normally used to kill a process, posix_kill really just sends a signal.
    // We'll send SIGCONT to wake up the other script
    posix_kill($pid, SIGCONT);
    

    And here's what it looks like in action. First in one terminal:

    $ php SleepingScript.php 
    93357
    

    And going to a second terminal:

    $ php WakeScript.php 93357
    

    And back to the original terminal:

    $ php SleepingScript.php 
    93357
    Interrupted by a signal.
    Time remaining: 111 seconds, 712678616 nanoseconds.