laravel 自定义 artisan 命令中分发的队列任务若抛出异常,默认不会触发全局异常处理器;正确做法是利用队列任务自身的 `failed()` 方法捕获失败,并在此处实现邮件通知等自定义逻辑。
在 Laravel 中,队列任务(Job)的异常处理机制与 HTTP 请求生命周期是分离的:即使你在 app/Exceptions/Handler.php 中已完善了全局异常捕获逻辑,该处理器仅作用于同步请求上下文(如 Web 或 API 请求),而不会介入队列进程(如 php artisan queue:work)中的异常流转。因此,当 Artisan 命令中调用 dispatch() 发送任务后,若任务执行时抛出未捕获异常,Laravel 不会委托给 Handler::render() 或 Handler::report(),而是直接标记为失败并交由队列系统处理。
✅ 正确方案:使用任务类内置的 failed() 方法
每个可队列任务(实现了 ShouldQueue 接口)都支持定义 failed(Throwable $exception) 方法。该方法会在任务达到最大重试次数(默认 1 次)后自动调用,且保证只执行一次,是处理最终失败场景的理想入口:
$exception->getMessage(),
'trace' => $exception->getTraceAsString(),
]);
// 发送告警邮件(示例使用 Mail facade)
Mail::raw("Job failed: {$exception->getMessage()}\n\n" . $exception->getTraceAsString(), function ($message) {
$message->to('admin@example.com')
->subject('[Laravel Queue Alert] ProcessOrder Job Failed');
});
}
}? 前置准备:
php artisan queue:failed-table php artisan migrate
⚠️ 注意事项:
vel Horizon(可视化监控)或 Sentry(错误追踪)增强可观测性; 总结:Laravel 队列的健壮性依赖于其原生失败处理契约。放弃“让 Handler.php 拦截队列异常”的思路,转而拥抱 failed() 钩子,不仅能精准捕获最终失败原因,还能解耦异常通知逻辑,使系统更可靠、可维护。