升级Python/Psycopg2/Gunicorn后Django站点出现cursor已关闭错误求助
解决Django站点随机出现
InterfaceError: cursor already closed错误的排查方向 问题描述
我们运行着一个Django 4.0.4站点,自从将Python从3.10升级至3.11、Psycopg2从2.8.6升级至2.9.3/5、Gunicorn从20.0.4升级至20.1.0后,代码库的随机位置频繁出现随机的InterfaceError: cursor already closed错误,很少重复出现在同一行,大约每5-10k次运行出现一次,虽概率较低但每天仍会发生几次。此前该站点已稳定运行1-2年未出现此错误,目前无法确定游标断开的原因及排查方向。
版本信息
- Python版本:3.11
- Psycopg版本:2.9.3 / 2.9.5
- PostgreSQL版本:12.11
- Gunicorn版本:20.1.0
排查方向
1. 数据库连接池与线程安全问题
- 检查DATABASES配置中的
CONN_MAX_AGE设置,Python 3.11的线程模型或Gunicorn 20.1.0的worker管理可能导致旧连接被复用后游标异常。尝试将CONN_MAX_AGE调小(比如设为60),或暂时设为0禁用连接复用,观察错误是否消失。 - 确认是否有自定义的数据库连接/游标操作逻辑,未遵循Django的ORM规范(比如手动创建游标后未正确关闭,或在多线程环境下共享连接对象)。
2. Psycopg2版本兼容性问题
- Python 3.11对Psycopg2的支持在早期2.9版本可能存在边缘case,尝试降级到Psycopg2 2.9.6或升级到最新的2.9.x稳定版,查看官方changelog中是否有针对Python 3.11的游标修复。
- 检查是否开启了Psycopg2的
autocommit模式,升级后该模式的行为是否有变化,导致游标被意外关闭。
3. Gunicorn Worker配置问题
- 对比Gunicorn 20.0.4和20.1.0的配置差异,尤其是worker类型(sync/gevent/gthread)和worker数量。如果使用gthread,Python 3.11的线程调度变化可能引发连接资源竞争,可尝试切换回sync worker,或调整worker数量、线程数。
- 检查Gunicorn的
timeout参数,若超时时间过短,可能导致worker被重启时连接未正确释放,遗留的游标对象被后续请求复用。
4. PostgreSQL端的连接状态排查
- 在PostgreSQL中执行
SELECT * FROM pg_stat_activity;,观察是否有异常断开的连接,或长时间空闲的连接被数据库端主动关闭。可调整PostgreSQL的idle_in_transaction_session_timeout参数,避免事务空闲过久导致游标失效。 - 查看PostgreSQL日志,是否有连接断开的错误信息(如
FATAL: terminating connection due to administrator command),这可能是数据库端主动关闭了连接。
5. Django ORM的隐性游标操作
- 检查是否有使用
raw()查询、cursor()上下文管理器外的手动游标操作,这些场景下若未正确处理异常,可能导致游标未被关闭或连接状态异常。 - 升级Django到4.0.x的最新补丁版本(如4.0.10),Django 4.0.4可能存在与Python 3.11兼容的小问题,官方后续补丁可能修复了游标管理的bug。
内容的提问来源于stack exchange,提问作者Kushboy
相关产品推荐
相关产品推荐

