Laravel Horizon中失败任务未自动重试问题排查求助
我有一个SendEmailMessage任务,已设置public $tries = 2;,但任务失败后并未自动重试,只能在Horizon中手动重试。
任务代码
class SendEmailMessage implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; private $message; public $tries = 2; public function __construct(EmailMessage $message) { $this->message = $message; } public function handle(EmailMessageRepository $emailMessageRepository) { app()->setLocale($this->message->organization->locale); $emailMessageRepository->send($this->message); } }
队列配置
'email' => [ 'driver' => 'redis', 'connection' => 'default', 'queue' => 'email', 'retry_after' => 90, 'block_for' => null, ],
Horizon Supervisor配置
'supervisor-2' => [ 'connection' => 'redis', 'queue' => ['media', 'email', 'sms'], 'balance' => 'simple', 'processes' => 1, 'tries' => 2, ],
排查与解决思路
检查异常是否被捕获吞掉
Laravel队列仅会对未被捕获的异常触发自动重试。如果$emailMessageRepository->send()方法内部捕获了邮件发送相关的异常(比如连接超时、服务器错误)但没有重新抛出,任务会被标记为执行成功,自然不会触发重试。需要确保发送逻辑中的异常能够冒泡到任务的handle方法外。确认
retry_after配置逻辑
队列的retry_after设置为90秒,这个参数是当任务执行时长超过90秒时,Laravel会判定任务超时失败并重新入队。如果你的任务是在90秒内抛出异常,这个配置不影响重试,但如果任务执行时间过长导致被强制标记失败,需要确保该值大于任务正常执行的最大时长。验证Horizon配置是否生效
Horizon Supervisor中的tries配置优先级高于任务类的tries,但你两者都设置为2,所以数值上没有冲突。需要确认Horizon是否已重启,确保新的配置被加载(可以执行php artisan horizon:terminate后重新启动Horizon)。查看任务失败详情
在Horizon的失败任务列表中查看任务的执行次数和失败原因:如果任务已经执行了2次(初始执行+1次重试)后进入失败列表,说明重试逻辑正常;如果仅执行1次就失败,那还是异常未触发重试的问题。检查Horizon Worker状态
执行php artisan horizon:status确认worker进程是否正常运行,若进程卡住或未启动,重启Horizon即可。
内容的提问来源于stack exchange,提问作者Martin Drapeau

