Keep in mind that you can easily and selectively prevent signal types of your choosing (including SIGALRM) from interrupting blocking operations you don't want interrupted. Use pcntl_sigprocmask() to shield any part of your code, whenever needed and without affecting expected signal behavior for the rest of it.
Here is simple example of shielding one blocking sleep operation from being interrupted while allowing it to happen to another - right next to each other.
<?php
$alarm = 2;
$sleep = 10;
$stamp = time();
pcntl_async_signals(TRUE);
pcntl_signal(SIGALRM, function(int $sig) use ($alarm, &$stamp) {
$late = (($now = time()) - $stamp) - $alarm;
$stamp = $now;
echo '* ALARM SIGNAL HANDLER * Fired '. ($late ? ($late .' seconds late') : 'on schedule') .' *'. PHP_EOL;
pcntl_alarm($alarm);
});
function get_some_sleep(int $duration, string $info) {
$start = time();
echo PHP_EOL . $duration .' seconds sleep - '. $info . PHP_EOL;
sleep($duration);
$early = $duration - (time() - $start);
echo 'Sleep was '. ($early ? ('interrupted. Woke up '. $early .' seconds early.') : 'uninterrupted.') . PHP_EOL;
}
pcntl_alarm($alarm);
while (TRUE) {
get_some_sleep($sleep, 'without a shield');
pcntl_sigprocmask(SIG_BLOCK, [SIGALRM]);
get_some_sleep($sleep, 'protected by sigprocmask()');
pcntl_sigprocmask(SIG_UNBLOCK, [SIGALRM]);
}