У меня есть PHP-скрипт, который работает бесконечно, и я пытаюсь сделать так, чтобы он мог корректно завершить работу при получении сигнала SIGTERM. Этот скрипт является частью большой кодовой базы Symfony2, поэтому «скрипт» на самом деле является сервисом, который запускается командой. В принципе, у меня есть логическое значение в классе обслуживания $shouldBeAlive
, у меня есть while(true)
цикл, который проверяет, если $shouldBeAlive
все еще верно в начале каждой итерации. Затем у меня есть обработчик сигнала, который устанавливается непосредственно перед while(true)
цикл запускается, что, если SIGTERM брошен, устанавливает $shouldBeAlive
в false, чтобы цикл завершил свою текущую итерацию и сразу же завершил работу в начале следующей итерации.
В моем понимании сигналов и еще много чего, все это должно работать нормально. Но вместо этого я получаю сообщение Segmentation fault: 11
каждый раз, когда я отправляю SIGTERM в процесс php (который я делаю с kill <pid>
). Я пытался использовать трассировки Xdebug, чтобы найти источник проблемы, но я не смог выяснить очевидную проблему из этого (также, файл трассировки, генерируемый Xdebug, составляет 8-10 МБ).
Вот упрощенная версия моего класса обслуживания:
class WorkerService extends AbstractService
{
private $shouldBeAlive;
// called by the constructor of this class
protected function setup()
{
$this->shouldBeAlive = false;
}
// called when my command wants to make the work begin
public function go()
{
$this->shouldBeAlive = true;
// set signal handler to `$this->handleSignal($signo)`
assert(pcntl_signal(SIGTERM, [$this, "handleSignal"]));
$this->work();
}public function handleSignal($signo)
{
// make the worker terminate on next loop completion
$this->shouldBeAlive = false;
// restore the default handler for this signal
assert(pcntl_signal($signo, SIG_DFL));
echo "Signal received, shutting down gracefully... (send signal again to force immediate shutdown)";
return;
}
public function work()
{
while (true) {
// make PHP fire any waiting signals
pcntl_signal_dispatch();
// break out of the loop if we're supposed to be dead
if (!$this->shouldBeAlive) break;
// ...
// I'm omitting the actual loop logic. Basically, it makes some
// HTTP requests, sometimes starts another process with proc_open(),
// and eventually it'll sleep for a couple seconds and continue.
}
}
}
Кажется, что мой метод handleSignal ($ signo) вообще никогда не вызывается, так как никакие изменения не устраняют проблему. Я также пытался использовать declare(ticks = 1);
в методе go () вместо вызова pcntl_signal_dispatch();
в цикле while (true), и он все еще сегрегируется (и, как я понимаю, делать это таким образом не имеет смысла в любом случае). Кто-нибудь видит, что я могу упустить или недоразумение?
Задача ещё не решена.
Других решений пока нет …