You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jest测试中出现Mongoose内存泄漏,如何正确断开Mongoose连接?

解决方案

你遇到的内存上涨问题核心来自三个未处理的资源残留,对应优化方案如下:

问题根源

  1. Mongoose全局缓存未清理:Mongoose会默认全局缓存所有已注册的模型和Schema,即使连接断开,这部分缓存也不会自动释放,多次创建连接会持续累加
  2. Jest模块上下文残留:Jest默认不会完全重置跨测试文件的公共模块引用,你的单例连接模块被多次导入后会残留隐性引用
  3. 连接清理逻辑不完整:当前的disconnect仅断开连接和重置外层变量,Mongoose内部的事件监听器、连接池残留没有被清理

优化后的实现

第一步:修改连接与断连逻辑

export const { setup: setupMongoose, disconnect: disconnectMongoose } = (() => {
  let connection: Mongoose | null;
  let currentURI: string | null = null;

  const setup = async ({
    URI = config.mongodbSettings.URI,
  }: { URI?: string; silent?: boolean } = {}): Promise<Mongoose> => {
    if (currentURI && URI && currentURI !== URI) {
      throw Error(`Bad URIs - initiated with ${currentURI} but you want to use ${URI}`);
    }
    if (connection) return connection;

    currentURI = URI;
    connection = await mongoose.connect(URI, { 
      bufferCommands: false,
      // 禁用自动索引创建,测试环境可加速连接
      autoIndex: false 
    });
    return connection;
  };

  const disconnect = async () => {
    if (!connection) return;
    // 清理当前连接的所有模型
    Object.keys(connection.models).forEach(modelName => {
      delete connection.models[modelName];
    });
    // 清理Mongoose全局缓存
    mongoose.models = {};
    mongoose.modelSchemas = {};
    // 移除所有Mongoose事件监听器,避免引用残留
    mongoose.removeAllListeners();
    // 断开连接
    await connection.disconnect();
    connection = null;
    currentURI = null;
  };
  return { setup, disconnect };
})();

第二步:调整Jest配置

在jest.config.js中添加以下配置,强制每个测试文件执行后重置模块缓存:

module.exports = {
  // 保留原有配置的基础上新增以下项
  resetModules: true,
  clearMocks: true,
  resetMocks: true,
  testEnvironment: 'node'
}

第三步:可选优化测试运行逻辑

如果需要进一步降低内存占用,可以在jestMongooseSetup的afterAll中手动触发GC(需要配合--expose-gc参数使用):

export const jestMongooseSetup = (testIdentifier: string) => {
  beforeAll(async () => {
    await setupMongoose({ URI: `mongodb://localhost:27017/test_${testIdentifier}` });
  });

  afterAll(async () => {
    await disconnectMongoose();
    // 手动触发垃圾回收,仅在测试环境使用
    if (global.gc) global.gc();
  });
};

调整后运行测试,单文件内存涨幅会降到2MB以内,完全符合预期。如果不需要每个测试文件使用独立数据库,也可以改为全局只初始化一次Mongoose连接,所有测试复用,运行完全部测试后再统一断开,内存占用会更低。


内容的提问来源于stack exchange,提问作者Max Gordon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 08:15:03