Метод failed
Метод failed класса Job вызывается автоматически,
когда задача из очереди не может быть выполнена после всех попыток.
В качестве аргумента метод принимает исключение, которое было выброшено при выполнении задачи.
Этот метод позволяет реализовать дополнительную логику обработки ошибок:
сохранение информации о сбое в лог, отправка уведомлений разработчикам,
запись данных в базу для последующего анализа.
Синтаксис
<?php
namespace App\Jobs;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ExampleJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, SerializesModels;
public function handle(): void
{
// Логика выполнения задачи
}
public function failed(\Throwable $exception): void
{
// Логика обработки ошибки
}
}
?>
Пример
Создадим задачу для отправки письма пользователю. Если письмо не удалось отправить после нескольких попыток, запишем ошибку в лог и отправим уведомление администратору:
<?php
namespace App\Jobs;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
class SendWelcomeEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected User $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function handle(): void
{
Mail::to($this->user->email)->send(new \App\Mail\WelcomeMail($this->user));
}
public function failed(\Throwable $exception): void
{
Log::error('Failed to send welcome email to user ' . $this->user->id, [
'error' => $exception->getMessage(),
'user_id' => $this->user->id
]);
// Отправка уведомления администратору
\App\Models\FailedJob::create([
'job' => self::class,
'user_id' => $this->user->id,
'error' => $exception->getMessage()
]);
}
}
?>
Пример
Если задача выполняет несколько операций, можно разделить обработку ошибок в зависимости от типа исключения:
<?php
namespace App\Jobs;
use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
class ProcessOrder implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected Order $order;
public function __construct(Order $order)
{
$this->order = $order;
}
public function handle(): void
{
// Обработка заказа
$this->order->update(['status' => 'processing']);
// Внешний API запрос
$res = $this->callExternalApi();
$this->order->update(['status' => 'completed']);
}
protected function callExternalApi(): array
{
// Симуляция внешнего API
if (rand(0, 1) === 0) {
throw new \Exception('External API unavailable');
}
return ['status' => 'success'];
}
public function failed(\Throwable $exception): void
{
if ($exception instanceof \Exception && strpos($exception->getMessage(), 'External API') !== false) {
Log::warning('External API error for order ' . $this->order->id, [
'order_id' => $this->order->id,
'error' => $exception->getMessage()
]);
$this->order->update([
'status' => 'api_error',
'error_message' => $exception->getMessage()
]);
} else {
Log::error('Critical error processing order ' . $this->order->id, [
'order_id' => $this->order->id,
'error' => $exception->getMessage()
]);
$this->order->update(['status' => 'critical_error']);
}
}
}
?>
Пример
Метод failed также полезен для отправки уведомлений в мессенджеры или системы мониторинга:
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use App\Services\SlackService;
class GenerateReport implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected int $userId;
public function __construct(int $userId)
{
$this->userId = $userId;
}
public function handle(): void
{
// Генерация отчета
$reportData = $this->generateData();
// Сохранение отчета в файл
file_put_contents('/tmp/report_' . $this->userId . '.json', json_encode($reportData));
}
protected function generateData(): array
{
// Симуляция сложной операции
if (rand(0, 2) === 0) {
throw new \RuntimeException('Memory limit exceeded');
}
return ['user_id' => $this->userId, 'data' => [1, 2, 3, 4, 5]];
}
public function failed(\Throwable $exception): void
{
// Логирование в файл
Log::channel('report_failures')->error('Report generation failed', [
'user_id' => $this->userId,
'error' => $exception->getMessage()
]);
// Уведомление в Slack
$slack = app(SlackService::class);
$slack->sendMessage('⚠️ Report generation failed for user #' . $this->userId);
// Очистка временных файлов
$filePath = '/tmp/report_' . $this->userId . '.json';
if (file_exists($filePath)) {
unlink($filePath);
}
}
}
?>
Результат выполнения кода в логе:
"Report generation failed for user #42"
Смотрите также
-
метод
handle,
который выполняет основную логику задачи -
атрибут
tries,
который определяет количество попыток выполнения задачи -
атрибут
timeout,
который устанавливает время ожидания выполнения задачи -
интерфейс
ShouldQueue,
который указывает, что задача должна быть выполнена в очереди