hyperf异步队列需分层设置timeout和handle_timeout,前者控制投递等待(建议设2秒),后者约束任务执行(必须显式设≥10秒);禁用阻塞调用,io操作须用wait_for加超时保护且值小于handle_timeout;启用重试、熔断及队列隔离。

Hyperf异步队列任务执行卡死、超时未中断、协程堆积导致服务雪崩——这些问题不是配置没写对,而是超时策略没分层设计。你得先明确:timeout控制投递等待,handle_timeout才真正约束任务执行时间,两者缺一不可。
设置两个关键超时参数
打开 config/autoload/async_queue.php,找到 default 配置块:
把 'timeout' 设为 2(单位秒),这是任务投递进 Redis 队列前的等待上限;【handle_timeout 必须显式设为 10 或更高】,否则任务一旦进入消费流程,就不再受 timeout 约束,可能无限阻塞协程。
若 handle_timeout 留空或为 0,Hyperf 默认用 PHP 的 max_execution_time,而协程环境下该值失效,任务将彻底失控。
避免协程退化为同步阻塞
在 Job 类的 handle() 方法里,禁止出现以下三类调用:
① sleep()、usleep()、time_nanosleep() 等原生阻塞函数;
② 未设超时的 curl_exec()、file_get_contents()、PDO::query();
③ 同步 Redis 客户端调用(如 phpredis 的 get()),必须改用 Hyperf\Redis\Redis 协程客户端。
只要混入任意一项,task_enable_coroutine=true 就形同虚设,协程立刻降级为单线程阻塞,handle_timeout 失效。
用 wait_for 包装高风险 IO 操作
方法一:在 handle() 内部对网络请求加 asyncio-style 超时保护
使用 Hyperf 的协程超时工具:Co::set(['socket_connect_timeout' => 3, 'socket_read_timeout' => 5]);
方法二:对关键 HTTP 请求套一层 try-catch + wait_for
调用 $response = Co::wait(fn() => $this->httpClient->get($url), 8.0); —— 这里 8.0 是最大等待秒数,超时后自动 cancel 协程,不占用 worker。
【wait_for 的 timeout 值必须小于 handle_timeout】,否则外层超时永远触发不了。
启用失败重试与熔断降级
第一步:在 async_queue.php 中开启重试机制
'retry_seconds' => 60,表示失败后 60 秒再入队;
'max_attempts' => 3,超过三次直接进死信队列。
第二步:对非核心任务(如日志上报、埋点)启用熔断
在 handle() 开头加入 if ($this->circuitBreaker->canCall()) { ... },失败率超 40% 且持续 60 秒即熔断,跳过执行直接返回。
第三步:核心任务(如支付回调确认)必须配独立队列和更高并发 limit,严禁与非核心任务共用 default 队列。











