Laravel任务调度本身不支持重试,重试逻辑必须由队列任务实现;需定义Job类、设置$tries或retryUntil()、使用Redis/Database驱动、启用失败表、合理配置Worker参数,并按错误类型差异化重试。

Laravel 任务调度本身不直接支持重试机制,它只负责“什么时候触发任务”,而重试逻辑必须落在被调度的 Job 类内部。换句话说:调度器(scheduler)管定时,队列(queue)管执行与重试。
重试必须由队列任务承载
你不能对 $schedule->command('inspire') 或 $schedule->call(...) 直接设重试次数。正确做法是把实际逻辑封装成一个队列任务,再让调度器去分发它:
- 定义任务类:
php artisan make:job SendDailyReport - 在任务类中设置重试属性和策略,例如:
$tries = 3;
public function handle() { $this->retryUntil(now()->addSeconds(10)); ... } - 在
App\Console\Kernel.php的schedule()方法中调用:$schedule->job(new SendDailyReport)->dailyAt('09:00');
关键配置项必须协同生效
仅写 $tries = 3 不够,还需确保底层队列驱动支持并配合超时控制:
-
驱动必须是 redis 或 database(不能是 sync),且
config/queue.php中对应连接的retry_after值(如 Redis 默认 90 秒)要大于任务内retryUntil()设定的时间 -
失败表必须启用:运行
php artisan queue:failed-table && php artisan migrate,否则失败记录无法持久化,重试状态不可追溯 -
Worker 启动参数要合理:使用
--sleep=0减少失败感知延迟,用--max-jobs=100防止内存泄漏
按错误类型做差异化重试
在任务的 failed() 方法中,不要无脑重发。应判断异常性质再决策:
- 遇到网络类异常(
ConnectException、RedisException、HTTP 502/503)可快速重试:dispatch($this)->delay(now()->addMilliseconds(200)); - 遇到业务规则错误(如
InvalidOrderStateException、重复 ID、参数非法)应直接终止,记录日志,不再重试 - 避免在
failed()中无条件调用dispatch($this),否则可能引发失败雪球,撑爆 Redis 内存
补充:调度任务本身失败怎么办?
如果调度命令执行失败(比如 php artisan schedule:run 进程崩溃),Laravel 不会自动重试该调度动作。你需要靠系统级守护来保障调度器稳定:
- Linux 下用 cron 每分钟调一次
php artisan schedule:run - 或用 Supervisor 守护
schedule:run进程(需额外配置) - 注意:这属于基础设施层容错,和队列任务的重试是两个层级


















