noCursorTimeout=True仅禁用游标空闲超时(10分钟),但无法防止30分钟会话超时;单批处理超时、Atlas M0/Flex不支持、未刷新会话或batch_size过大均会导致CursorNotFound错误。

noCursorTimeout=True 为什么不能彻底防超时?
它只禁用游标空闲超时(默认10分钟),但不管会话超时——而 MongoDB 默认会话生命周期是30分钟。只要单批处理耗时超过30分钟(比如调外部API、解析大JSON、写慢盘),哪怕设了 no_cursor_timeout=True,游标照样被服务器静默关闭,报错 CursorNotFound。
常见错误现象:pymongo.errors.CursorNotFound: cursor id 123456789 not found,尤其在长循环里调用 parse_data() 这类函数时高频出现。
注意:MongoDB Atlas 的 M0/Flex 集群直接不支持 no_cursor_timeout,设了也无效。
batch_size() 是更实际的防线
batch_size() 不是“延长超时”,而是把一次大遍历切分成多个小批次,每批拉完后驱动自动发新请求,相当于重置空闲计时器。
实操建议:
- 从
batch_size(1000)起手,观察单批平均耗时;若稳定在60秒内,可逐步加到5000或10000 - 务必搭配
no_cursor_timeout=True使用(两者不冲突,是协同关系) - 避免设过大(如
batch_size(100000)):可能触发 OOM,且单批卡住仍会跨过30分钟会话上限
Python 示例:collection.find({}, no_cursor_timeout=True).batch_size(5000)
跑几小时的任务必须管住会话生命周期
光靠 no_cursor_timeout 和 batch_size 不够——30分钟会话过期仍是隐形炸弹。
正确做法是显式创建会话并定期刷新:
- 用
client.start_session()创建会话,再把查询绑定进去 - 每25分钟左右调一次
client.admin.command("refreshSessions", [session.session_id]) - 会话ID 必须从
session.session_id动态取,别硬编码 - 异常时记得手动调
session.end_session(),否则会话残留占用资源
别碰 cursorTimeoutMillis 全局配置
有人搜到 db.adminCommand({ setParameter: 1, cursorTimeoutMillis: 300000 }) 想一劳永逸——这方案要重启 mongod,在生产环境基本不可行;而且它只影响空闲游标,对会话超时和单批处理超时完全无效。
真正复杂的地方在于:你得同时盯住三个时间维度——游标空闲计时器(10分钟)、会话生命周期(30分钟)、单批处理耗时(必须远小于30分钟)。三者只要一个掉链子,CursorNotFound 就准时报到。


















