Как выполнить действие после завершения всех заданий в очереди в Laravel?

«Как выполнить действие после завершения всех заданий в очереди в Laravel?» — вопрос из категории Laravel, который задают на 24% собеседований PHP Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В Laravel есть несколько способов выполнить действие после обработки всей очереди или цепочки заданий.

1. Использование метода then() для цепочек (Job Chains): Это наиболее прямой способ для цепочек заданий, созданных через Bus::chain().

use IlluminateSupportFacadesBus;

$chain = [
    new ProcessPodcast,
    new OptimizePodcast,
    new ReleasePodcast
];

Bus::chain($chain)->then(function () {
    // Это замыкание выполнится после успешного завершения ВСЕХ заданий в цепочке.
    Log::info('All podcast processing jobs completed.');
    // Например, отправить уведомление пользователю.
})->dispatch();

2. Использование события Queue::after для глобального обработчика: Вы можете зарегистрировать глобальный обработчик в AppServiceProvider, который сработает после успешного выполнения ЛЮБОГО задания.

// В методе boot() AppServiceProvider.php
use IlluminateSupportFacadesQueue;
use IlluminateQueueEventsJobProcessed;

Queue::after(function (JobProcessed $event) {
    // $event->job содержит экземпляр задания
    // $event->job->payload() содержит данные задания
    // Это выполнится после каждого успешного задания.
});

3. Использование метода finally() для цепочек (на случай успеха или провала): Метод finally() выполнится в любом случае, даже если задание в цепочке завершилось неудачно.

Bus::chain($chain)
    ->then(function () { /* при успехе */ })
    ->catch(function () { /* при ошибке */ })
    ->finally(function () {
        // Выполнится всегда. Полезно для финальной очистки.
    })->dispatch();

Почему then() для цепочек предпочтительнее? Он обеспечивает четкую, связанную логику, которая выполняется атомарно после конкретной группы заданий, а не после каждого отдельного задания в системе.