协程超时后资源不会自动释放,必须手动控制生命周期并显式清理;超时仅表示拿不到连接,协程仍运行,context数据、redis连接、未exec的pipeline等持续滞留,需通过try/finally、withpipeline或transaction等机制保障清理。

Hyperf 协程本身没有自动超时回收机制,超时请求不会被框架主动终止或清理资源——你必须自己控制协程生命周期,否则连接、Context 数据、对象实例都会滞留。
协程超时后资源真的会被释放吗
不会。协程超时(比如 wait_timeout 抛出 WaitTimeoutException)只是“拿不到连接”的信号,不代表当前协程结束,更不触发任何资源清理:
-
Co\Redis或Co\MySQL实例持有的 socket 句柄仍被该协程独占,直到协程真正退出 -
Context::set()写入的数据不会自动清空,后续同协程内逻辑仍可读取 - 未
unset的对象、未close()的客户端、未exec()的 pipeline 都继续存活 - 若该协程是长周期的(如 WebSocket 连接、定时任务),泄漏可能持续数分钟甚至更久
怎么让超时请求真正“干净退出”
靠手动加超时控制 + 显式清理,不能依赖框架或 Swoole 自动行为:
- 用
Co::sleep($seconds)+try/finally包裹关键操作,确保即使超时也能执行$redis->close()或Context::del() - 对 Redis pipeline/multi,必须用
withPipeline()(Hyperf 3.1+)或try/finally { $redis->exec() },避免异常跳过exec() - 数据库事务建议配合
Connection::transaction(),它内部已封装了 rollback + release 逻辑 - 自定义耗时逻辑,可用
hyperf-alarm-clock库在超时点抛出异常并捕获,在catch块里做清理
wait_timeout 设置不当会掩盖真实问题
wait_timeout 不是协程超时开关,它只控制“等连接”的最大容忍时间:
- 设太小(如
0.1):大量WaitTimeoutException,但实际连接池可能只是瞬时抖动 - 设太大(如
10.0):请求卡住十几秒才失败,掩盖了max_connections不足、pipeline 泄漏或 MySQL gone away 导致的上下文污染 - 推荐值
2.0–5.0:给连接释放留缓冲,又能在堆积时快速暴露瓶颈 - 验证是否真缺连接:用
swoole_get_local_socket_count()看 ESTABLISHED 数是否长期贴近max_connections
最易被忽略的是:超时异常发生后,协程还在跑,而你写的 catch 里没做任何清理——此时泄漏已开始,且不会报错,只会慢慢拖垮服务。











