【问题标题】:How to close database connection in nestjs service?如何在nestjs服务中关闭数据库连接?
【发布时间】:2020-12-24 10:51:30
【问题描述】:

在我的数据库模块中,我正在创建与我的数据库的连接。有了这个设置,我确实得到了错误

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

在我的 e2e 测试中。

我想我必须关闭连接。但是如何在我的数据库模块中的onModuleDestroy() 中运行client.close

database.module.ts

import { Module } from '@nestjs/common'
import { MongoClient, Db, Logger } from 'mongodb'

@Module({
    providers: [
        {
            provide: 'DATABASE_CONNECTION',
            useFactory: async (): Promise<Db> => {
                const mongo = 'mongodb://localhost:27017'
                const database = 'testing'

                try {
                    Logger.setLevel('debug')

                    const client = await MongoClient.connect(mongo, {
                        useNewUrlParser: true,
                        useUnifiedTopology: true,
                    });

                    const db = client.db(database)
                    return db
                } catch (error) {
                    throw error
                }
            }
        },
        {
            provide: 'DATABASE_CLIENT',
            useFactory: () => true // how do I get client of the above provider?
        }
    ],
    exports: ['DATABASE_CONNECTION', 'DATABASE_CLIENT']
})

export class DatabaseModule {
    constructor(
        @Inject('DATABASE_CLIENT')
        private client: Db
    ) {}

    async onModuleDestroy() {
        console.log(this.client);
        // await this.client.close()
    }
}

【问题讨论】:

  • 很可能是的,这就是问题所在。在钩子中进行清理,docs.nestjs.com/fundamentals/lifecycle-events。我猜是 onModuleDestroy。
  • @EstusFlask 但是当数据库模块返回db 而不是client 时,我该如何关闭客户端?请查看有关服务代码的更新帖子。
  • 这需要在数据库服务或模块中完成,而不是在消费者中,模块有责任自行清理。是的,您需要为此保留对client 的引用。可能有一个单独的提供商{ provide: 'DATABASE_CLIENT' useFactory: () =&gt; ({ client: null }) }。将其注入 DATABASE_CONNECTION 以分配客户端属性,并注入 DatabaseModule 以在 onModuleDestroy 中访问它。我不确定在 Nest 中执行此操作的最佳方法是什么,如果 db 服务是一个类会更容易。
  • 注入到 DATABASE_CONNECTION 是什么意思?您能否将 db 服务作为一个类发布一个示例?
  • 我的意思是使用DI将客户端服务注入连接工厂。我发布了代码。我无法确认它是否可行,但我希望它或多或少会以这种方式完成。

标签: javascript testing jestjs nestjs


【解决方案1】:

打开的数据库连接是导致此问题的常见原因。一个模块需要自己清理,这尤其适用于一个模块可以被多次实例化的测试。

client 需要保留引用以进行清理。这可以通过单类服务来完成:

@Injectable()
class DatabaseConnection {
  async onModuleInit() {
    // ...same as DATABASE_CONNECTION factory
    this.client = client;
    this.db = client.db(database);
  }
  async onModuleDestroy() {
    await this.client.close()
  } 
}

或者使用两个工厂提供者,其中一个保留对client 的引用:

@Module({
  providers: [
    {
      provide: 'DATABASE_CLIENT',
      useFactory: () => ({ client: null })
    },
    {
      provide: 'DATABASE_CONNECTION',
      inject: ['DATABASE_CLIENT'],
      useFactory: async (dbClient) => {
        ...
        dbClient.client = client
        const db = client.db(database)
        return db;
      }
    }
  ]
  ...
})
export class DatabaseModule {
  constructor(@Inject('DATABASE_CLIENT') private dbClient) {}

  async onModuleDestroy() {
    await this.dbClient.client.close()
  } 
}

【讨论】:

  • 它必须是await this.dbClient.client.close(),因为 dbClient 有对象客户端。您必须为第一个提供者使用对象吗?
  • 我正在写评论。最后对你有用吗?我希望两个解决方案是等效的,并且在这两种情况下都会调用 onModuleDestroy。是的,这是一个错字,它应该有 client 属性。是的,必须有一个对象来传递对client 的引用,这是 JS 中的一个流行配方。
  • 谢谢。是的,它运行良好。抱歉,已删除评论。但这只是缺少的财产,我首先没有认出。
  • 很高兴它有帮助。考虑编辑问题,它缺少最初发布的测试代码,因此其他读者可能不清楚上下文。
猜你喜欢
  • 2018-08-29
  • 2021-07-19
  • 2021-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-01
  • 1970-01-01
相关资源
最近更新 更多