如何在 Laravel 队列任务失败时自动发送异常告警邮件

如何在 Laravel 队列任务失败时自动发送异常告警邮件

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');
        });
    }
}

? 前置准备:

  1. 运行以下命令创建 failed_jobs 表(Laravel ≥ 5.7 默认需要):
    php artisan queue:failed-table
    php artisan migrate
  2. 确保队列驱动配置正确(如 database、redis),并在 .env 中设置 QUEUE_CONNECTION=redis(或其他);
  3. 启动队列监听器:php artisan queue:work –tries=3(建议显式指定重试次数,避免无限重试)。

⚠️ 注意事项:

Jaaz

Jaaz

开源的AI设计智能体

下载

  • 不要在 handle() 方法中用 try-catch 吞掉异常并静默返回——这会绕过失败机制,导致 failed() 不被触发;
  • 若需差异化处理不同异常类型(如 StripeException vs ConnectionException),可在 failed() 中使用 instanceof 判断并定制邮件模板或通知渠道;
  • 对于关键任务,建议结合 Laravel Horizon(可视化监控)或 Sentry(错误追踪)增强可观测性;
  • failed() 方法本身不应再抛出异常,否则可能导致队列进程崩溃;如有必要,应内部捕获并记录。

总结:Laravel 队列的健壮性依赖于其原生失败处理契约。放弃“让 Handler.php 拦截队列异常”的思路,转而拥抱 failed() 钩子,不仅能精准捕获最终失败原因,还能解耦异常通知逻辑,使系统更可靠、可维护。

https://www.php.cn/faq/1969551.html

发表回复

Your email address will not be published. Required fields are marked *