hyperf定时任务数据库连接超时本质是连接池未适配长周期协程生命周期,需独立配置schedule连接池、启用heartbeat(设为max_idle_time/2)、max_idle_time严格小于mysql wait_timeout、事务兜底释放、禁用min_connections=0。

Hyperf定时任务里数据库连接超时,本质不是“任务慢”,而是连接池在长周期协程中失效未清理、心跳未启用、或连接被服务端主动断开后仍被复用。修复关键在于让连接池适配定时任务的生命周期——它不走HTTP请求短平快路径,而是常驻运行,必须主动保活、及时回收、独立隔离。
定时任务必须用独立数据库连接池
默认复用HTTP接口的db连接池,会导致冷启动时连接数不足、长任务期间连接老化、异常中断后上下文污染等问题。应为定时任务单独配置连接池:
- 在
config/autoload/db.php中新增一个名为schedule的数据库配置项 - 设置
'pool' => ['min_connections' => 5, 'max_connections' => 20](避免与接口争抢连接) - 在定时任务类中显式指定连接:
DB::connection('schedule') - 确保
config/autoload/schedule.php中的任务调用方式不隐式使用默认连接
必须开启并配准 heartbeat + max_idle_time
定时任务协程可能持续数分钟甚至小时,MySQL 默认 wait_timeout(通常300–600秒)会悄悄关闭空闲连接,而Hyperf默认不主动探测。需协同配置:
- 查 MySQL 实际值:
SHOW VARIABLES LIKE 'wait_timeout'; - 设
'max_idle_time' => 270(比 wait_timeout 小30秒) - 设
'heartbeat' => 135(推荐 max_idle_time / 2) - 禁用
'checker' => 'SELECT 1',优先用原生 PING(驱动支持时更轻量)
事务与异常必须兜底释放连接
定时任务常含批量操作、循环更新、条件分支,一旦中间 throw Exception 且没 finally,连接不会自动归还,导致后续任务反复复用已失效连接:
- 所有 DB 操作包裹在
try {} finally { DB::connection()->getPdo()->close(); }不现实,应改用事务块兜底 - 正确写法:
DB::connection('schedule')->transaction(function () { /* 业务逻辑 */ }, 3); - 若手动控制事务,务必在 catch 后显式
DB::connection()->rollBack(),并在 finally 中确保DB::purge('schedule')(仅必要时) - 避免在事务中混用 Redis 或 HTTP 客户端,防止协程上下文污染扩散
连接超时参数要区分场景调优
定时任务对响应延迟容忍度高,但对连接稳定性要求更高,不能沿用接口的激进参数:
-
'connect_timeout' => 5.0(网络抖动时比默认10秒更早失败,避免卡死) -
'wait_timeout' => 5.0(协程等连接时间,设太小易误报,太大掩盖泄漏) -
'options' => [PDO::ATTR_TIMEOUT => 3](单条SQL执行超时,防慢查询拖垮整个任务) - 禁用
'pool' => ['min_connections' => 0],至少设为 3~5,保障冷启动有可用连接











