生产环境必须使用Redis、database或SQS等支持原生超时的队列驱动,sync驱动会忽略所有timeout设置;需配置QUEUE_CONNECTION、retry_after≥timeout,并通过$timeout属性、timeout()方法或--timeout参数设定任务超时;同时用--memory、--max-jobs、--max-time防止内存泄漏,retryUntil()实现时效敏感重试。

确认队列驱动是否支持超时控制
生产环境必须使用 Redis、database 或 SQS 等支持原生超时机制的驱动,【sync 驱动会忽略所有 timeout 设置,任务立即同步执行】。检查 .env 文件中 QUEUE_CONNECTION=redis(或 database),再验证 config/queue.php 中对应连接的 retry_after 值已显式配置且大于 0。
若仍用 sync 驱动上线,所有 timeout 属性和 --timeout 参数均失效,任务卡死将直接阻塞整个请求进程。
设置单个任务的最长执行时间
方法一:在任务类中声明 $timeout 属性
打开 App\Jobs\YourJob.php,在类体顶部添加 protected $timeout = 180; 表示该任务最多运行 180 秒。
方法二:分发时动态指定超时值
在控制器中调用 dispatch()->timeout(240):SendInvoiceEmail::dispatch($order)->timeout(240); 这个值会覆盖任务类中的 $timeout。
方法三:启动 worker 时统一设定
执行 php artisan queue:work --timeout=120;该值将作为所有未显式设置 $timeout 的任务的兜底限制。
【retry_after 必须 ≥ timeout,否则任务可能被重复执行】。例如 timeout=120,则 config/queue.php 中 redis → retry_after 至少设为 120,推荐设为 150 以留出确认写入缓冲时间。
防止内存泄漏导致隐性超时
第一步:为 worker 添加内存硬限制
启动命令中加入 --memory=128,表示当进程内存占用超过 128MB 时自动退出并由 Supervisor 重启。
第二步:限制单个 worker 处理总任务数
追加 --max-jobs=500 参数,避免因闭包引用、静态变量累积导致内存持续增长。
第三步:设定 worker 最大存活时间
加上 --max-time=3600,强制 worker 每运行 1 小时重启一次,切断潜在的资源泄漏链。
Supervisor 配置中需启用 autorestart=true,否则 worker 退出后不会自动拉起,队列将停滞。
用 retryUntil() 替代 tries 实现时效敏感重试
对于必须在某个绝对时间点前完成的任务(如“订单创建后 30 分钟内完成支付校验”),不要用 $tries = 3,而应实现 retryUntil() 方法:
public function retryUntil()
{
return now()->addMinutes(30);
}
该方法返回一个 DateTime 对象,Laravel 会在每次失败后检查当前时间是否早于该时间戳,早于则重试,否则丢弃任务。【retryUntil() 仅在抛出未捕获异常时触发,return false 或静默 exit 不会重试】。


















