Symfony4中GOS WebSocketBundle启用PDO周期Ping仍遇MySQL连接断开错误
我来帮你搞定这个问题——你碰到的Error while sending QUERY packet和MySQL server has gone away本质上都是MySQL连接因超时被服务器主动关闭导致的,哪怕启用了PDO周期性Ping,大概率是配置或者执行逻辑没踩对关键点。下面是针对性的排查和解决步骤:
检查PDO Ping间隔是否小于MySQL超时参数
MySQL默认的wait_timeout和interactive_timeout通常是8小时,但很多开发环境会改短。你必须确保WebSocket配置的PDO Ping间隔严格小于这两个参数的值——比如如果MySQL的wait_timeout是3600秒(1小时),那Ping间隔要设成3000秒左右,给服务器留缓冲时间。
先通过MySQL命令查看当前超时值:SHOW VARIABLES LIKE '%timeout';再核对GOS WebSocketBundle的Ping配置:
gos_web_socket: server: pdo: ping_interval: 3000 # 单位:秒,必须小于MySQL的wait_timeout # 其他PDO相关配置...确保Ping操作绑定到每个WebSocket连接的PDO实例
WebSocket是长连接,每个客户端连接对应独立的PDO连接(如果你的业务逻辑是每个连接用单独DB连接的话)。要确认Bundle的Ping机制是针对每个连接的PDO实例执行,而不是全局共享一个实例——如果是共享连接,Ping可能只保活了全局连接,长时间闲置的客户端连接对应的DB连接还是会超时断开。开启Doctrine自动重连机制
哪怕Ping没覆盖到所有场景,也可以让Doctrine在检测到连接失效时自动重连。在Doctrine配置里开启auto_reconnect:doctrine: dbal: connections: default: # 其他数据库配置... options: PDO::ATTR_PERSISTENT: false # 注意:持久化连接可能和Ping机制冲突,建议关闭 auto_reconnect: true在DB操作前主动校验连接有效性
对于WebSocket里的业务逻辑,每次执行数据库操作前,可以手动触发PDO的ping()方法,确保连接是存活状态:// 在你的WebSocket Handler类中 $connection = $this->entityManager->getConnection(); if (!$connection->ping()) { $connection->close(); $connection->connect(); } // 之后再执行你的数据库操作调整MySQL超时参数(备选治标方案)
如果上面的方法都没解决,可以临时调大MySQL的wait_timeout和interactive_timeout(比如改成7200秒/2小时),但这只是临时缓解,建议优先从应用层解决连接保活问题。修改MySQL配置文件(my.cnf或my.ini)后重启服务:wait_timeout = 7200 interactive_timeout = 7200
内容的提问来源于stack exchange,提问作者Serghei

