Laravel Artisan CLI безопасно останавливает рабочие очереди демонов

Чтобы обработать большое количество заданий, я запускаю переменное количество обработчиков очереди в зависимости от того, сколько работы нужно выполнить. Я не хочу запускать больше воркеров, чем необходимо для завершения работы, которую необходимо выполнить за период времени, который мы считаем подходящим.

На данный момент я запускаю 5 воркеров очереди демонов для целей тестирования, однако в продакшене это число может быть от 25 до 100 воркеров, возможно, больше. Я понимаю, что при развертывании я должен остановить обработчиков очереди, сначала переведя фреймворк в режим обслуживания с помощью php artisan down, потому что флаг --daemon заставляет фреймворк загружаться только при запуске обработчика, поэтому новый код не будет действовать во время развернуть, пока рабочий не перезапустится.

Если бы мне по какой-то причине нужно было остановить рабочих, я мог бы перевести приложение в режим обслуживания, используя php artisan down, что приведет к смерти рабочих после того, как они закончат обработку своей текущей работы (если они работают над ней). Однако могут быть случаи, когда я хочу убить рабочих, не переводя все приложение в режим обслуживания.

Есть ли безопасный способ остановить рабочие процессы таким образом, чтобы они продолжали выполнять свою текущую работу, а затем умирали, не переводя все приложение в режим обслуживания?

По сути, мне нужен php artisan queue:stop, который ведет себя как php artisan queue:restart, но не перезапускает рабочий процесс после завершения работы.

Я ожидал, что будет такая команда php artisan queue:stop, которая сделает это, но, похоже, это не так.

Используя ps aux | grep php, я могу получить идентификаторы процессов для рабочих, и я мог бы убить процессы таким образом, но я не хочу убивать процесс в середине его работы над заданием.

Спасибо.


person Vigs    schedule 05.05.2015    source источник
comment
Для тех, кто найдет этот вопрос. stackoverflow.com/questions/30060526/ содержит ответ. php artisan queue:restart остановит рабочие процессы. Название перезапуска вводит в заблуждение. Рабочие на самом деле не будут перезапускаться после того, как они были остановлены.   -  person Vigs    schedule 14.10.2015
comment
верно. Перезапуск происходит только в том случае, если у вас есть что-то вроде настройки Supervisor для мониторинга и автоматического перезапуска их после их выхода. (Это типичная установка.)   -  person Trevor Gehman    schedule 22.04.2016


Ответы (4)


Мы реализовали что-то подобное в нашем приложении, но это не было встроено в сам Laravel. Вам нужно будет отредактировать этот файл. , добавив еще одно условие в блок if, чтобы он вызывал функцию stop. Вы можете сделать это, либо установив статическую переменную в классе Worker, которая будет изменяться всякий раз, когда вы запускаете пользовательскую команду, которую вам нужно будет сделать (например, php artisan queue:pause), либо проверив атомарное значение где-нибудь (т.е. установите его в каком-то кеше, таком как redis , memcached, APC или даже MySQL, хотя это будет означать, что у вас будет один запрос MySQL для каждого цикла этого цикла while), который вы устанавливаете с помощью одной и той же пользовательской команды.

person Nikko    schedule 07.05.2015
comment
Я боялся, что мне придется сделать что-то подобное. Придется настроить redis или memcache, проверка флага - это пустая трата запроса, особенно когда это происходит для каждой итерации в цикле с 25-100 работниками. Лучший ответ у меня есть, так что +. Надеюсь, они добавят что-то подобное в более поздних версиях. - person Vigs; 07.05.2015
comment
Да, лучше всего использовать APC/redis/memcached, причем APC лучше всего подходит в этой ситуации. - person Nikko; 15.05.2015

При использовании флага --daemon рабочие не должны уходить, когда очередь пуста.

Я думаю, что вы ищете в документации по очередям.

Команда php artisan queue:restart предложит воркерам перезапуститься после того, как они закончат свою текущую работу.

person Deinumite    schedule 06.05.2015
comment
Правильно, я не хочу, чтобы рабочие останавливались, когда очередь пуста. Что я хочу сделать, так это остановить работников очереди по команде, но сделать это безопасно, чтобы они не останавливались в середине обработки задания. php artisan queue:restart, к сожалению, не делает того, что мне нужно. Я не собираюсь перезапускать рабочих, я хочу безопасно их остановить. Документация не содержит никакой информации об остановке обработчика очереди, в ней просто упоминается, что вам, возможно, придется сделать это вручную. - person Vigs; 07.05.2015
comment
По сути, мне нужен php artisan queue:stop, который ведет себя как php artisan queue:restart, но не перезапускает работника после выполнения задания. - person Vigs; 07.05.2015
comment
Откройте терминал с помощью php artisan queue:work --daemon и запустите php artisan queue:restart в другом терминале. Первый терминал на самом деле просто отключится через некоторое время. На самом деле он не перезапускает его, это зависит от отдельного процесса, такого как supervisord.org. - person Deinumite; 07.05.2015

Начиная с Laravel 5.5 существует событие Illuminate\Queue\Events\Looping, которое запускается из вызова daemonShouldRun() внутри основного рабочего цикла Illuminate\Queue\Worker. Таким образом, если вы настроите прослушиватель для проверки следует обрабатывать задания и вернете false, то обработчики очереди остановятся до тех пор, пока проверка не вернет значение true. Между следующей проверкой есть пауза, которую вы можете настроить, передав --sleep <seconds> в команду queue:work.

В настоящее время я использую эту технику во время развертывания, чтобы остановить воркеры, которые работают внутри контейнеров докеров, поскольку не так просто запустить на них предложенный queue:restart без взлома.

person alexkb    schedule 05.05.2019

мой Laravel 5.6. вы можете (убить свой pid) не волнуйтесь, потеряете свою работу, просто загрузите pcntl (расширение) Laravel может прослушать сигнал и безопасно выйти

показать исходный код ниже (в ./vendor/laravel/framework/src/Illuminate/Queue/Worker.php):

protected function listenForSignals()
{
    pcntl_async_signals(true);

    pcntl_signal(SIGTERM, function () {
        $this->shouldQuit = true;
    });

    pcntl_signal(SIGUSR2, function () {
        $this->paused = true;
    });

    pcntl_signal(SIGCONT, function () {
        $this->paused = false;
    });
}

И мой тест ниже:

for($i=0; $i<100; $i++){
        pcntl_async_signals(true);

    pcntl_signal(SIGTERM, function () {
        echo 'SIGTERM';
    });

    pcntl_signal(SIGUSR2, function () {
        echo 'SIGUSR2';
    });

    pcntl_signal(SIGCONT, function () {
        echo 'SIGCONT';
    });
echo $i; 
sleep(1);
 }

можешь попробовать убить

person Zuo Zou    schedule 10.06.2019
comment
Jup не недооценивает важность расширения pcntl и следит за тем, чтобы ваш сигнал уничтожения не был установлен на SIGKILL (по умолчанию на официальных изображениях Docker PHP), а исправлял SIGTERM! - person Maarten de Graaf; 18.03.2021