Как выполнить действие в конце очереди в Laravel?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Управление очередями в Laravel: выполнение действий в конце
В Laravel существует несколько подходов для выполнения действия в конце очереди, то есть после того, как все остальные задачи были обработаны. Вот основные методы:
1. Использование обратного вызова then()
Метод then() объекта PendingChain или PendingBatch позволяет задать колбэк, который выполнится после завершения всех задач в цепочке или пакете.
use App\Jobs\ProcessPodcast;
use Illuminate\Support\Facades\Bus;
Bus::chain([
new ProcessPodcast,
new OptimizePodcast,
new ReleasePodcast,
])->then(function () {
// Этот код выполнится после успешного завершения ВСЕХ задач
Podcast::where('processed', false)->update(['status' => 'completed']);
Mail::to('admin@example.com')->send(new QueueCompletedMail());
})->dispatch();
2. Использование событий и слушателей
Laravel предоставляет системные события для мониторинга работы очередей:
// В сервис-провайдере
protected $listen = [
'Illuminate\Queue\Events\JobProcessed' => [
'App\Listeners\LogJobProcessed',
],
'Illuminate\Queue\Events\WorkerStopping' => [
'App\Listeners\HandleWorkerStop',
],
];
// Пример слушателя для завершения работы воркера
class HandleWorkerStop
{
public function handle($event)
{
if ($event->worker->shouldQuit || $event->status === 'stopped') {
// Выполнить финальные действия
$this->cleanupTempFiles();
$this->sendNotification();
}
}
}
3. Пакетная обработка с методом finally()
Для пакетной обработки задач можно использовать метод finally():
use App\Jobs\ProcessVideo;
use Illuminate\Bus\Batch;
use Illuminate\Support\Facades\Bus;
Bus::batch([
new ProcessVideo('video1.mp4'),
new ProcessVideo('video2.mp4'),
new ProcessVideo('video3.mp4'),
])->then(function (Batch $batch) {
// Выполнится при успешном завершении всех задач
})->catch(function (Batch $batch, Throwable $e) {
// Выполнится при возникновении ошибки
})->finally(function (Batch $batch) {
// Выполнится ВСЕГДА после завершения пакета
// Независимо от успеха или ошибки
Storage::deleteDirectory('temp/videos');
Log::info('Batch processing completed');
})->dispatch();
4. Создание финального джоба в цепочке
Вы можете создать специальный джоб, который будет выполняться последним:
class FinalCleanupJob implements ShouldQueue
{
public function handle()
{
// Выполнить финальные действия
Cache::forget('queue_last_run');
DB::table('queue_logs')->insert(['completed_at' => now()]);
}
}
// Использование в цепочке
Bus::chain([
new ProcessData,
new ValidateData,
new FinalCleanupJob, // Финальный джоб
])->dispatch();
5. Кастомные воркеры и middleware
Для сложных сценариев можно создать кастомный воркер или middleware:
class QueueTerminationMiddleware
{
public function handle($job, $next)
{
try {
$response = $next($job);
} finally {
// Этот код выполнится после каждой работы джоба
if (app()->runningInConsole() && app('queue.worker')->shouldQuit) {
$this->executeFinalActions();
}
}
return $response;
}
}
Ключевые моменты для выбора подхода:
then()иfinally()— идеальны для цепочек и пакетов задач- Системные события — подходят для глобального мониторинга очередей
- Финальные джобы — простой и понятный подход для последовательностей
- Middleware — дает максимальный контроль, но сложнее в реализации
Рекомендации по использованию:
- Для простых последовательностей используйте метод
then()в цепочках - Для гарантированного выполнения независимо от результата используйте
finally() - Для глобального логирования и мониторинга используйте системные события
- Для сложной бизнес-логики создавайте специализированные финальные джобы
- Всегда добавляйте обработку ошибок и таймаутов для финальных операций
Выбор конкретного метода зависит от вашего сценария использования, требований к надежности и сложности бизнес-логики. Для большинства случаев методов then() и finally() будет достаточно.