【问题标题】:jest mongoose causing memory leak开玩笑的猫鼬导致内存泄漏
【发布时间】:2020-12-31 00:18:13
【问题描述】:

2020 年 9 月 14 日更新

我有一个我编写的示例测试用例。当我运行这段代码时,测试用例通过了,但它抱怨说拆解没有正确发生并且有一个打开的连接。任何人都可以发现它是什么:

方法 1 - 内存泄漏

import { Connection, createConnection } from 'mongoose';
import __MONGO_URI__ from './__MONGO_URI__';

let conn: Connection | null = null;

const getConnection: (MONGO_DB_NAME: string) => Promise<Connection> = async MONGO_DB_NAME => {
  if (conn == null) {
    conn = await createConnection(__MONGO_URI__, {
      dbName: MONGO_DB_NAME,
      bufferCommands: false, // Disable mongoose buffering
      bufferMaxEntries: 0, // and MongoDB driver buffering
      useNewUrlParser: true,
      useUnifiedTopology: true,
      useCreateIndex: true
    });
  }
  return conn;
};

const MONGO_DB_NAME = 'mongo-test';
let db: Connection;

describe('mongo - connection test to ensure setup teardown', () => {
  beforeAll(async done => {
    db = await getConnection(MONGO_DB_NAME);
    done();
  });
  afterAll(async done => {
    if (conn) {
      await db.dropDatabase();
      await conn.close();
    }
    done();
  });
  it('true = true', () => {
    expect(true).toBe(true);
  });
});

错误:

工作进程未能正常退出并被强制退出。这可能是由于不正确的拆卸导致测试泄漏造成的。尝试使用 --runInBand --detectOpenHandles 运行以查找泄漏。

如果我把它全部剥离出来:

方法 2 - 内存泄漏

import { Connection, createConnection } from 'mongoose';
import __MONGO_URI__ from './__MONGO_URI__';

let conn: Connection | null = null;

const getConnection: (MONGO_DB_NAME: string) => Promise<Connection> = async MONGO_DB_NAME => {
  if (conn == null) {
    conn = await createConnection(__MONGO_URI__, {
      dbName: MONGO_DB_NAME,
      bufferCommands: false,
      bufferMaxEntries: 0,
      useNewUrlParser: true,
      useUnifiedTopology: true,
      useCreateIndex: true
    });
  }
  return conn;
};

const MONGO_DB_NAME = 'mongo-test';
let db: Connection;

describe('mongo - connection test to ensure setup teardown', () => {
  beforeAll(async () => {
    db = await getConnection(MONGO_DB_NAME);
    console.log('db = ', db);
  });
  it('true = true', () => {
    expect(true).toBe(true);
  });
});

我还是有同样的问题

或者甚至这样做同样的问题:

方法 3 - 内存泄漏

import { Connection, createConnection } from 'mongoose';
import __MONGO_URI__ from './__MONGO_URI__';

let conn: Connection | null = null;

const getConnection: (MONGO_DB_NAME: string) => Promise<Connection | null> = MONGO_DB_NAME =>
  new Promise(resolve => {
    if (conn == null) {
      conn = createConnection(__MONGO_URI__, {
        dbName: MONGO_DB_NAME,
        bufferCommands: false,
        bufferMaxEntries: 0,
        useNewUrlParser: true,
        useUnifiedTopology: true,
        useCreateIndex: true
      });
      conn.on('connected', () => {
        console.log('connected?');
        resolve(conn);
      });
    }
    resolve(conn);
  });

const MONGO_DB_NAME = 'mongo-test';
let db: Connection;

describe('mongo - connection test to ensure setup teardown', () => {
  beforeAll(async () => {
    db = await getConnection(MONGO_DB_NAME);
    console.log('db = ', db);
  });
  it('true = true', () => {
    expect(true).toBe(true);
  });
});

这种方法也有同样的问题

方法 4 - 内存泄漏

import mongoose from 'mongoose';
import __MONGO_URI__ from './__MONGO_URI__';

let conn: typeof mongoose;

const getConnection: (MONGO_DB_NAME: string) => Promise<typeof mongoose> = async MONGO_DB_NAME => {
  if (!conn) {
    conn = await mongoose.connect(__MONGO_URI__, {
      dbName: MONGO_DB_NAME,
      // bufferCommands: false,
      // bufferMaxEntries: 0,
      // useNewUrlParser: true,
      // useUnifiedTopology: true,
      // useCreateIndex: true
    });
  }
  return conn;
};

const MONGO_DB_NAME = 'mongo-test';
let db: typeof mongoose;

describe('mongo - connection test to ensure setup teardown', () => {
  beforeAll(async () => {
    db = await getConnection(MONGO_DB_NAME);
    console.log('db = ', db);
  });
  it('true = true', () => {
    expect(true).toBe(true);
  });
});

【问题讨论】:

  • 那么,使用--runInBand --detectOpenHandles 运行的输出是什么?
  • 没有错误输出吗? asyncdone 是一种反模式。应该是async 一个人。如果 dropDatabase 失败并且未达到关闭状态,则可能会出现问题。
  • --runInBand --detectOpenHandles 实际上并没有显示任何内容并且卡住并且没有退出测试
  • @EstusFlask 感谢您的反馈。导致内存泄漏的不是删除数据库或关闭连接。这是连接的实际创建。 createConnection 导致内存泄漏。如果我去掉代码只是为了shi。即使我删除了异步等待。
  • 这不是连接本身导致泄漏,而是它被打开而不是关闭的事实。 Mongoose 连接肯定可以关闭,并且它们可以毫无问题地用于 Jest 测试。方法 2-4 在隔离问题方面没有任何价值,因为它们甚至不尝试关闭连接。按照我建议的方式尝试,去掉done,因为它有缺陷并且可以抑制错误。调试await conn.close() 真的被调用了。这是我在这里看到的唯一可能的问题。

标签: typescript mongoose async-await jestjs


【解决方案1】:

最终解决方案 - 感谢:@EstusFlask

getMongoConnection.ts

import { Connection, createConnection } from 'mongoose';
import __MONGO_URI__ from './__MONGO_URI__';

let conn: Connection | null = null;

const getConnection: (MONGO_DB_NAME: string) => Promise<Connection | null> = MONGO_DB_NAME =>
  new Promise(resolve => {
    if (conn == null) {
      conn = createConnection(__MONGO_URI__, {
        dbName: MONGO_DB_NAME,
        bufferCommands: false,
        bufferMaxEntries: 0,
        useNewUrlParser: true,
        useUnifiedTopology: true,
        useCreateIndex: true
      });
      conn.on('connected', () => {
        resolve(conn);
      });
    }
    resolve(conn);
  });

export default getConnection;

mytest.test.ts

import { Connection } from 'mongoose';
import getConnection from './getMongoConnection';

let db: Connection | null;

const MONGO_DB_NAME = 'mongo-test';
const collectionName = 'users';

describe('mongo - connection test to ensure setup teardown', () => {
  beforeAll(async () => {
    db = await getConnection(MONGO_DB_NAME);
  });
  afterAll(async () => {
    if (db) {
      await db.dropDatabase();
      await db.close();
    }
  });
  it('should insert a doc into collection', async () => {
    if (db) {
      const users = db.collection(collectionName);

      const mockUser = { _id: 'some-user-id', name: 'John' };
      await users.insertOne(mockUser);

      const insertedUser = await users.findOne({ _id: 'some-user-id' });
      expect(insertedUser).toEqual(mockUser);
    }
  });
});

【讨论】:

    猜你喜欢
    • 2022-08-20
    • 2019-04-08
    • 2018-06-11
    • 1970-01-01
    • 2015-07-06
    • 2014-06-07
    • 2013-11-20
    • 2011-10-28
    • 2016-01-18
    相关资源
    最近更新 更多