如何在Laravel Job尝试因超时被终止时执行代码(Horizon)
捕获Laravel Job每次尝试的超时事件
要捕获Job每次尝试的超时并执行日志记录、用户通知,你可以通过以下方式实现:
核心思路
Laravel Job超时会抛出Illuminate\Queue\TimeoutException,你可以在handle方法中包裹业务逻辑并捕获该异常,结合attempts()方法判断当前尝试次数(小于总重试次数时),执行自定义逻辑后重新抛出异常,让队列系统正常触发重试流程。
代码实现
use Illuminate\Queue\TimeoutException; use Throwable; class MyJob implements ShouldQueue { public $tries = 3; public $timeout = 600; // [...] public function handle() { try { // 这里编写你的Job核心业务逻辑 $this->executeBusinessLogic(); } catch (TimeoutException $e) { // 获取当前尝试次数,从1开始计数 $currentAttempt = $this->attempts(); // 仅在非最后一次尝试时执行通知与日志记录 if ($currentAttempt < $this->tries) { // 记录超时日志 logger()->warning("Job [{$this->job->getJobId()}] 第{$currentAttempt}次执行超时,即将进行重试"); // 执行用户通知(示例:替换为你的实际通知逻辑) // UserAlert::send($targetUser, "任务执行超时,系统正在自动重试"); } // 重新抛出异常,确保队列系统触发重试流程 throw $e; } catch (Throwable $e) { // 如需处理其他异常导致的重试,可在此添加逻辑 // 同样判断尝试次数后执行操作,再抛出异常触发重试 throw $e; } } public function failed(Throwable $exception) { // 3次尝试全部失败后的最终处理逻辑 logger()->error("Job [{$this->job->getJobId()}] 3次尝试均失败"); // 通知用户任务最终失败 } private function executeBusinessLogic() { // 你的具体业务代码 } }
额外说明
attempts()方法返回当前是第几次尝试(第一次执行返回1,第二次重试返回2,以此类推)。- 必须重新抛出异常,否则队列系统会判定Job执行成功,不会触发后续重试。
- 如果需要区分“超时重试”和“其他异常重试”,可以分别捕获对应异常类做针对性处理。
内容的提问来源于stack exchange,提问作者Ifnot
相关产品推荐
相关产品推荐

