根本原因是任务进程不自动继承数据库配置且未初始化连接池上下文,需显式获取ConnectionInterface、指定连接名、检查连接可用性、设置max_idle_time小于wait_timeout、确保事务/管道正确释放、验证连接池初始化。

Hyperf 任务进程(如异步队列 ConsumerProcess、自定义 Process)中调用数据库时出现连接异常(如 2006 MySQL server has gone away、Connection refused、Call to undefined method Db::connection()),根本原因不是“任务不能连库”,而是任务进程独立于 HTTP Worker 生命周期,**不自动继承默认数据库连接配置,也未初始化连接池上下文**。需显式指定连接、确保连接池就绪、并规避协程上下文隔离问题。
确认任务进程是否使用了正确的连接实例
Hyperf 3.0+ 已弃用 Db::connection() 全局访问器,任务进程中若仍沿用该写法会直接报错 Class not found 或方法不存在。必须通过 DI 容器获取连接对象:
- 注入
Hyperf\DbConnection\ConnectionInterface(推荐):
public function __construct(private ConnectionInterface $db) {} - 或手动从容器取:
$db = $this->container->get(ConnectionInterface::class); - 若需多库,须明确指定连接名(如
'mysql_log'):
$db = $this->container->get(ConnectionFactoryInterface::class)->get('mysql_log');
避免连接在协程间复用失效
任务进程常长期运行,空闲连接易被 MySQL 主动断开(wait_timeout 触发)。仅靠 pool.heartbeat 不足以保障——它只对连接池中的空闲连接生效,而任务进程若复用一个已取出但长时间未提交的连接,心跳不会触发。
- 每次数据库操作前,建议主动检查连接可用性(尤其长周期任务):
if (!$db->getPdo()->ping()) { $db->reconnect(); } - 更稳妥做法:将耗时操作拆分为短事务,避免单次 handle() 中持有一个连接超 30 秒
- 确保数据库连接池配置中
max_idle_time严格小于 MySQL 的wait_timeout(例如 MySQL 是 300s,则设max_idle_time => 270)
修复跨进程/跨协程的连接泄漏
异步任务中若使用了 pipeline、transaction 或手动 beginTransaction(),但未正常 commit/rollback 或未释放资源,会导致连接卡在当前协程上下文中,后续任务无法获取新连接。
- 所有事务块必须配
try/catch/finally,确保最终调用$db->commit()或$db->rollBack() - Redis 管道同理:使用
$redis->pipeline()后,必须调用exec()或在finally中重置:
finally { $redis->reset(); } - 不要在任务中长期持有 PDO 实例或自定义连接对象,应即用即取
验证连接池是否在任务进程内真正初始化
某些情况下(如配置中心未就绪、Redis 连接池提前初始化失败),任务进程启动时数据库连接池尚未构建完成,导致首次调用报连接异常。
- 在任务类
handle()开头加简单探测:
var_dump($this->db->query('SELECT 1')->fetch()); - 若报错,检查
config/autoload/db.php是否正确加载,且无语法错误 - 确认
processes.php中注册的 ConsumerProcess 在服务启动时能完整加载依赖(可加--debug启动观察日志)


















