Hyperf异步队列超时由timeout、handle_timeout、retry_seconds三重机制协同控制;timeout控制Redis阻塞读等待时间,默认2秒,handle_timeout控制单Job执行上限,默认10秒,二者须显式配置且handle_timeout需大于最慢同步操作耗时;retry_seconds支持固定延迟或指数退避重试;需禁用同步阻塞调用、为外部依赖设独立超时、确保Redis read_timeout≥timeout,并通过async-queue:info及sleep测试验证配置生效。

Hyperf异步队列超时机制直接决定任务是否被丢弃、重试或卡死,错误配置会导致订单关闭失败、邮件未发送、库存未回滚等线上事故;它不是简单的“时间到了就执行”,而是由 pop 超时、处理超时、重试间隔三重阈值协同控制的协程级调度行为。
理解 timeout 与 handle_timeout 的分工
timeout 控制消费者从 Redis 阻塞读取消息的最长等待时间,单位秒,默认值 2;handle_timeout 控制单个 Job 执行的最大耗时,单位秒,默认值 10。
若 timeout 设为 0,消费者会立即返回空结果,频繁轮询浪费 CPU;设得过大(如 30),在低流量时段会导致消费者进程长时间挂起,无法响应 SIGTERM 信号,重启卡住。
handle_timeout 必须严格大于任务内最慢的同步操作耗时——比如调用一次外部 HTTP 接口平均耗时 3 秒,那 handle_timeout 至少设为 5,否则协程会被强制终止,且不触发 retry_seconds 重试逻辑,任务直接进 failed 队列。
【timeout 和 handle_timeout 都必须显式配置,不能依赖默认值】
配置 retry_seconds 实现可控失败恢复
方法一:固定延迟重试
在 config/autoload/async_queue.php 中将 retry_seconds 设为整数,例如 60,表示每次失败后 60 秒重新入队。
方法二:指数退避重试
设为数组 [1, 3, 9, 27],每失败一次,下次重试延迟翻 3 倍;第 4 次失败后不再重试,进入 failed 队列。
注意:retry_seconds 数组长度必须 ≤ max_attempts 值,否则超出部分被忽略。
避免超时引发的协程阻塞
第一步:禁用所有同步阻塞调用
Job 类中严禁使用 file_get_contents、curl_exec、sleep() 等同步函数;必须改用 Hyperf\Guzzle\Client 或 Hyperf\HttpClient\CoroutineHttpClient 发起协程 HTTP 请求。
第二步:为外部依赖设置独立超时
即使 handle_timeout=10,若 Guzzle 客户端未设 timeout=3,则可能因远端无响应导致协程卡满 10 秒才被杀,期间无法处理其他消息。
第三步:检查 Redis 连接池 read_timeout ≥ 5
若 Redis 配置中 read_timeout 小于 timeout 值,消费者在阻塞 pop 时会提前断开连接,抛出 RedisException 并计入失败次数,触发非预期重试。
验证超时配置是否生效
运行命令 php bin/hyperf.php async-queue:info 查看当前队列状态,重点关注 running_processes 和 failed_count。
向队列投递一个故意 sleep(15) 的测试 Job,观察其是否在 handle_timeout 触发后进入 failed 队列,而非无限等待。
修改 retry_seconds 为 1,投递失败任务,确认其确实在 1 秒后重新出现在待消费队列头部,而非立刻重复执行。











