MongoDB watch随机崩溃提示Cursor session id与操作上下文session id不一致如何解决
错误触发原因
- 核心原因是MongoDB服务端会默认销毁闲置超过30分钟的会话,你创建的变更流(Change Stream)cursor绑定了旧的会话ID,会话失效后再发起请求就会出现会话ID不匹配的报错,附带的
Unauthorized错误码13是会话失效后的衍生提示,并非真实权限问题。 - 直接崩溃的原因是Node.js的EventEmitter机制要求所有
error事件必须绑定监听器,你仅监听了change事件,驱动内部抛出的错误没有被捕获,直接触发进程退出。
修复方案
1. 紧急兜底:给所有变更流添加error事件监听
首先添加监听避免进程崩溃,同时加自动重启逻辑保证监听可用性,代码示例如下:
单文档监听优化后代码
let watcher; async function startSingleDocWatch(documentId) { // 销毁旧实例避免内存泄漏 if (watcher) { try { await watcher.close(); } catch (e) { console.log('旧watcher关闭异常:', e.message); } } watcher = q.watch({ids: [documentId]}) .on("change", (changeEvent) => { if (changeEvent.operationType !== 'update') return; console.log('document was updated'); watcher.close().catch(e => console.log('watcher关闭异常:', e.message)); }) // 捕获错误避免进程崩溃,同时自动重启监听 .on('error', err => { console.error('单文档监听异常,3秒后自动重启:', err.message); setTimeout(() => startSingleDocWatch(documentId), 3000); }); }
集合插入监听优化后代码
let queueWatcher; async function startQueueWatch() { if (queueWatcher) { try { await queueWatcher.close(); } catch (e) { console.log('旧队列watcher关闭异常:', e.message); } } queueWatcher = queueCollection.watch([{ $match: { operationType: "insert" }}]) .on("change", (changeEvent) => { console.debug('document added', currentlyProcessing ? 'currentlyProcessing' : 'notCurrentlyProcessing'); if (!currentlyProcessing) processNextQueueItem(); }) .on('error', err => { console.error('队列监听异常,3秒后自动重启:', err.message); setTimeout(startQueueWatch, 3000); }); }
2. 连接配置优化(可选)
如果使用MongoDB 4.2及以上版本,可以在初始化MongoClient时调整会话配置,降低会话超时概率:
const client = new MongoClient(连接地址, { // 会话最大闲置时间设为29分钟,早于服务端默认30分钟的回收时间,避免拿到失效会话 sessionPool: { maxIdleTimeMS: 1740000 }, // 开启重试机制 retryReads: true, retryWrites: true })
3. 额外注意事项
如果是临时监听指定文档的变更,使用完成后一定要主动调用close()销毁watcher,避免闲置watcher占用资源同时触发超时错误。
内容的提问来源于stack exchange,提问作者stackers
相关产品推荐
相关产品推荐

