Troubleshooting Freezing Issues in a php Infinite Loop Script with Supervisor

45 Views Asked by At

I had an infinite loop that receives updates from a third-party service. This while loop is supervised, meaning that if it breaks, the script will be automatically restarted.

while (true) {
    try {
        // Long polling requests to retrieve messages from the bot
    } catch (BreakLoopException $exception) {
        break;
    }
}

However, I encountered a problem where the while loop would freeze on occasion. I suspected that this might be due to memory leaks. So, I adjusted my approach and decided to run the long polling logic in a separate process like this:

$round = 0;
while ($round < 100) {
    exec("php " . base_path() . "/artisan bot:get-updates");
    $round++;
}

Additionally, I made sure the while loop breaks automatically after 100 rounds, so the supervisor will restart it. Despite these changes, the script still froze, even though the while loop should have run 100 times only.

As of now, it has been 24 hours since the last script restart, which is quite unusual.

Why this is happening?

1

There are 1 best solutions below

0
volkerschulz On BEST ANSWER

Looks like your external program exec("php " . base_path() . "/artisan bot:get-updates"); freezes. I suggest to use PHP processes to have more control over the execution (including killing the external process if a timeout occurs).

For testing I used operation.php

<?php
echo 'TEST01' . PHP_EOL;
sleep(5);
echo 'TEST02' . PHP_EOL;

And called it with:

<?php

$command = 'php operation.php';
$timeout = 0.1; // Timeout in seconds

$descriptorspec = array(
    0 => array("pipe", "r"),
    1 => array("pipe", "w"),
    2 => array("pipe", "w") 
 );

for($i=0; $i<100; $i++) {
    $process = proc_open($command, $descriptorspec, $pipes);
    if(is_resource($process)) {
        $starttime = microtime(true);
        while(proc_get_status($process)['running']) {
            if((microtime(true)-$starttime) > $timeout) {
                proc_terminate($process);
                break;
            }
            usleep(10000); // Sleep for 10 ms
        }
        fclose($pipes[0]);
        $stdout = stream_get_contents($pipes[1]);
        fclose($pipes[1]);
        $stderr = stream_get_contents($pipes[2]);
        fclose($pipes[2]);
        $exit_code = proc_close($process);
        echo 'OUTPUT: ' . $stdout . PHP_EOL;
    }
    usleep(10000); // Sleep for 10 ms
}

which is going to output TEST01 but never TEST02, unless the $timeout is >5.