Процесс  queue:work  может завершиться по девяти разным причинам, и до выхода Laravel 13.30 вывод в консоль выглядел одинаково для всех случаев. Воркер, работающий под управлением Supervisor, который перезапускается каждые несколько минут, мог превысить лимит памяти, потерять соединение с базой данных или получить команду  queue:restart  после деплоя. Чтобы отличить эти ситуации друг от друга, приходилось регистрировать слушатель событий или сопоставлять время перезапуска с логами деплоя.

Теперь команда выводит причину в своей последней строке:

2026-09-01 13:20:40 Worker STOPPED Memory limit exceeded
 

#Вывод в консоль и JSON

Класс  WorkCommand  регистрирует слушатель для события  WorkerStopping  рядом с уже существующими слушателями статуса задач и очередей, поэтому строка остановки выводится в тех же двух форматах, что и остальной вывод. При использовании флага  --json  она представляет собой запись наряду со строками по каждой задаче:

{"level":"info","status":"stopped","reason":"empty","exit_code":0,"jobs_processed":12,"memory":34.0,"timestamp":"2026-09-01T13:20:40.118273+00:00"}
 

Поле  reason  содержит строковое значение enum, которое удобно использовать для фильтрации. Поле  memory  указывает объем в мегабайтах, округленный до одного знака после запятой, или  null , если воркер не зафиксировал этот показатель. Поле  level  принимает значение  info  при коде завершения 0 и  warning  во всех остальных случаях.

Эта строка не выводится при использовании флагов  --quiet  и  --silent , а также если причина равна null. Если воркер был принудительно завершен извне (например, механизмом OOM killer или сигналом  SIGKILL ), код, отправляющий событие, не успевает выполниться, поэтому такие завершения остаются незафиксированными в выводе.

#Причины остановки и коды завершения

 WorkerStopReason  — это уже существовавший ранее enum. Данное изменение добавило в него метод  description() , благодаря чему в консоли и в любых ваших слушателях используются одинаковые строки:

Значение Описание Код завершения
 empty  Очередь пуста 0
 empty_for  Очередь пуста в течение заданного времени 0
 max_jobs  Превышено максимальное количество задач 0
 max_time  Превышено максимальное время работы 0
 restart_signal  Получен сигнал перезапуска 0
 interrupted  Работа прервана 0
 lost_connection  Соединение потеряно 0
 memory  Превышен лимит памяти 12
 timed_out  Таймаут задачи 1

#Фильтрация JSON-вывода

Поскольку причина теперь является отдельным полем, найти её в логе можно с помощью простого фильтра:

php artisan queue:work --json --max-time=3600 2>&1 | \
    jq -c 'select(.status == "stopped")'
 

Если менеджер процессов записывает вывод в файл, этот же запрос можно выполнить по логам постфактум.

#Событие WorkerStopping

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

use Illuminate\Queue\Events\WorkerStopping;
 
Event::listen(function (WorkerStopping $event) {
    Log::info('Worker stopped', [
        'reason' => $event->reason?->value,
        'status' => $event->status,
        'jobs' => $event->jobsProcessed,
        'memory' => $event->memoryUsage,
    ]);
});
 

Используйте его, чтобы подсчитывать количество остановок по причинам для дашборда или отправлять эти данные в систему сбора метрик.

Автор пулл-реквеста: Jack Bayliss в #61339.