FrankenPHP 1.1 Worker模式下数据库连接超时主因是Caddy或MySQL主动断开空闲连接而PHP未及时感知,需协同配置Caddy keepalive、PDO持久连接及MySQL wait_timeout参数,并在请求结束时显式清理连接。

FrankenPHP 1.1 的 Worker 模式下数据库连接超时,本质不是 PHP 脚本执行慢,而是连接空闲被中间层或数据库主动断开后未及时感知和复用。关键要分清“谁在超时”——是 Caddy 断连?MySQL 关闭空闲连接?还是 PDO 本身卡在读写?处理需从三层协同入手。
查清超时源头:先看 Caddy 日志,再看 MySQL 状态
Worker 模式中,PHP 进程常驻,但 HTTP 连接由 Caddy 管理。很多“超时”实际是 Caddy 或 SLB 在无流量后静默关闭 TCP 连接,而 PHP 层仍试图复用已失效的 PDO 实例。
- 在 Caddyfile 中启用 debug 日志:
log { level debug },重启后搜connection closed、idle timeout、reset - 用
netstat -an | grep :3306 | wc -l持续观察连接数变化,缓慢上涨说明连接未释放;突然归零再飙升,说明被 MySQL 主动 kill - 登录 MySQL 执行
SHOW PROCESSLIST;,重点看Time列是否长期 > wait_timeout(默认 28800 秒),以及状态是否为Sleep
PDO 层必须启用持久连接并禁用自动关闭
默认每次请求新建 PDO,Worker 模式下会导致连接堆积或复用失效。Laravel/Symfony/ThinkPHP 都需显式配置:
- Laravel:在
.env加DB_PERSISTENT=true,并在config/packages/doctrine.yaml中补全:doctrine.dbal.connections.default.options: { pdo::ATTR_PERSISTENT: true, pdo::ATTR_EMULATE_PREPARES: false } - ThinkPHP:在
config/database.php的 MySQL 配置中设'persistent' => true - 禁用框架自动关闭行为:Laravel 确保
doctrine.dbal.auto_close为false;避免手动调用DB::connection()->getPdo()后不 unset
MySQL 侧参数必须匹配 Worker 并主动回收空闲连接
Worker 进程长期存活,依赖 MySQL 的 wait_timeout 自动断连不可靠。必须主动控制生命周期:
立即学习“PHP免费学习笔记(深入)”;
- 在
my.cnf中设:max_connections = 64(起步值,按num_threads × 5反推)wait_timeout = 60(缩短空闲容忍时间,配合应用层清理) - PDO DSN 中强制加超时参数(以 MySQLi 或 PDO MySQL 为例):
&connect_timeout=5&read_timeout=10&write_timeout=10 - 不要依赖
mysqlnd默认行为;若用 Laravel,可在config/database.php的options数组里直接传入超时键值
请求结束时必须显式清理连接资源
Worker 模式不会自动销毁 PDO 实例,上一个请求残留的连接可能在下一个请求中被误用或报 MySQL server has gone away:
- 在
frankenphp_handle_request()回调末尾,加逻辑判断连接状态:if ($pdo && $pdo->getAttribute(PDO::ATTR_CONNECTION_STATUS) === false) { $pdo = null; } - Laravel 用户应在每次请求后调用:
DB::purge('default')或DB::disconnect() - 避免在
register_shutdown_function中做清理——Worker 生命周期中该函数不可靠 - 每次请求处理完,立即调用
gc_collect_cycles(),防止连接对象长期驻留内存



















