Могу ли я рассчитывать на то, что register_shutdown_function () вызывается на SIGTERM, если установлена ​​функция pcntl_signal ()?

Я работаю над приложением, в котором периодически называются фоновые процессы. Один из них вызывался cron, но я ищу что-то более надежное, поэтому я конвертирую его для работы под Supervisor. (Вероятно, он будет работать в течение 10 минут, в течение которых он может обнаружить работу, которую нужно выполнить, или находится в режиме ожидания. После выхода Supervisor автоматически возродит чистый экземпляр.)

Поскольку Supervisor лучше обеспечивает параллельное выполнение только определенного количества экземпляров чего-либо, я могу избежать выполнения их дольше. Это, однако, означает, что мои процессы с большей вероятностью получат сигналы завершения, либо от kill напрямую или потому что они были остановлены через супервизора. Поэтому я экспериментирую с тем, как справиться с этим в PHP.

Похоже, что основным решением является использование pcntl_signal() вот так:

declare(ticks = 1);
pcntl_signal(SIGTERM, 'signalHandler');
pcntl_signal(SIGINT, 'signalHandler');

function signalHandler($signal) {
switch($signal) {
case SIGTERM:
case SIGINT:
echo "Exiting now...\n";
exit();
}
}

Тем не менее, у меня есть несколько моментов в моем коде, которые можно сделать с осторожной обработкой выключения. Один из подходов состоит в том, чтобы один обработчик вызывал эти разные вещи, но это потребовало бы некоторого рефакторинга, которого я хотел бы избежать. Альтернатива — добавить pcntl_signal() везде мне это нужно, но, к сожалению, кажется, что только один обработчик может быть установлен одновременно.

Тем не менее, похоже, что я может быть быть в состоянии использовать register_shutdown_function(). Это не ловушка ^C или другие прерывания подписываются сами по себе, и руководство вполне понятно по этому вопросу:

Функции выключения не будут выполняться, если процесс завершается с помощью сигнала SIGTERM или SIGKILL

Что удивительно, так это то, что если я найму pcntl_signal() просто сделать выход, то обработчики выключения являются действительно называется. Кроме того, поскольку можно иметь много обработчиков завершения работы, это прекрасно решает мою проблему — каждый класс в моем коде, который хочет корректно обрабатывать завершение, может захватывать и управлять своим собственным завершением работы.

Мой первый вопрос: почему это работает? Я попытался зарегистрировать функцию выключения без обработчика сигнала, и это, кажется, не вызывается, как говорится в руководстве. Я предполагаю, что процесс поддерживается PHP для обработки сигнала, который вызывает вызов обработчиков завершения работы?

Кроме того, могу ли я положиться на это поведение, когда руководство ставит под сомнение это? Я использую PHP 5.5, и пока не собираюсь обновляться до PHP7. Поэтому мне было бы интересно узнать, работает ли это на 5.5 и 5.6 в различных дистрибутивах.

Конечно, если это будет (или не будет) работать на 7.0 и / или 7.1, это тоже будет интересно — я знаю, что клещи будут обрабатываться по-разному в 7.1, поэтому есть большая вероятность того, что это будет иметь другое поведение.

17

Решение

Функции выключения пользователя PHP вызываются во время обычного завершения процесса, в некоторой степени аналогично функциям, зарегистрированным в atexit на других языках программирования. Явный exit или неявный выход в конце сценария является обычным завершением процесса.

Смерть сигнала, однако, является ненормальным завершением процесса. Поведение по умолчанию для SIGTERM (и обязательное поведение для SIGKILL) — немедленное завершение работающего процесса без запуска каких-либо обработчиков очистки.

Когда вы перехватываете SIGTERM с pcntl_signalВы устанавливаете другое поведение и даете себе возможность испытать обычное завершение процесса.

Да, вы можете положиться на это поведение. Хотя основная ручная запись не является явной, остальная часть «Заметки», которую вы цитируете, гласит:

[Ты можешь использовать pcntl_signal() установить обработчик для SIGTERM, который использует exit() закончить чисто.

7

Другие решения

Помимо пяток правильный ответ:

Обработчик сигнала необходим для изменения поведения сигнала (т.е. вместо действия по умолчанию). Что бы ни случилось после этого, не имеет значения.

Вы можете использовать обработчик сигнала, чтобы просто выполнить аварийную очистку, а затем вызвать posix_kill(getmypid(), SIGKILL); принудительно завершить без очистки. если ты exit() здесь обычно инициируется последовательность выключения (то есть вызов всех деструкторов, обработчиков выключения и т. д.).

Когда ты сказал в дополнение к, ты не совсем прав. Вам нужно использовать обработчик сигнала вместо и может дополнительно есть обработчик выключения. [ссылаясь на ваш комментарий]

Также знайте, что звонить exit() после того, как последовательность выключения была инициирована, прервет текущую ее часть (то есть, когда вы в данный момент находитесь в обработчике выключения и exit() вызывается, все последующие обработчики выключения игнорируются — но, например, деструкторы все равно будут называться). В идеале вы должны проверить это:

register_shutdown_function(function() { $GLOBALS["#__in_shutdown"] = 1; });

и проверить вокруг exit():

if (empty($GLOBALS["#__in_shutdown"])) {
exit;
}

На всякий случай, если вы хотите быть в полной безопасности, если кто-то не выстрелит в SIGKILL.

Обратите внимание, что 7.0 или 7.1 не изменят это поведение; все что меняется в 7.1 declare(ticks=1); излишнее, выставленное поведение остается прежним.

4

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector