王海鱼 发表于 2023-5-16 10:03:26

QueryFailedError: Connection Terminated

简单提一下这个问题,先讲思路,后面再进行深入的探索和解析和发散
事情发生在笔者开发某个typescript服务端项目的过程中。笔者需要将一个基于typeorm的读写数据库操作进行异步处理,也就是不阻塞当前线程。
大体是这样的一个行文:
// 用于typeorm的models文件中
class Person {
    @Column({ nullable: true })
    code: string | null = null;

    async initCode() {
      if (!this.code) return;
      
      this.code = randomAlphabet(); // 随机生成的code
    }
}

// 读写数据库文件中, eg: repos/person.ts
async function generateCode(person: Person): Promise<Person> {
    try {
      person.initCode();
    } catch (e) {
      // error catcher
    }
}

// 处理逻辑的controllers中,eg: controllers/personController.ts
async function generateCodeForPerson(ctx, next): Promise<void> {
    const person = await getPerson(ctx.params.id);
    void generateCode(person); // 这里不做await,选择异步处理
    ctx.code = 200;
}那么好,由于该项目比较重要,所以笔者所在项目组使用jest进行e2e测试,以确保api可用。同时会部署CI,用于在pull request过程中进行代码自测。
其中测试generateCode大致是这么一个走法:
describe('testGenerateCode', async () => {
    let runInBackgroundMock: jest.SpyInstance<
      void,
      
    >; // 这个是jest用于劫持运行函数中的函数后,将函数中的异步改同步的操作
    beforeAll(async () => {
      // 此处,将测试函数中所运行的utils.runInBackground方法进行mock,取消其异步性,将在未来笔记中深入讲解
      runInBackgroundMock = jest
            .spyOn(utils, 'runInBackground')
            .mockImplementation();
      initDB(); // 初始化CI过程中连接测试DB的Client,占用DB连接资源
    })
    /**
   * 此处不止一个describe
   */
    describe('should successful', async () => {
      await testGenerateCodeForPerson(); // 其中调用了generateCodeForPerson,但是比较深,所以当时没发现
    })
    afterAll(async () => {
      closeDB(); // 关掉DBClient,释放DB连接资源
    })
});细心的读者应该能够但从中发现问题了:万一没执行完generateCode的内容,就closeDB了,那不就出问题了?
没错!笔者遇到这个问题了,但第一时间没有意识到问题来自笔者的代码,下面是CI的报错:
https://img2023.cnblogs.com/blog/1936833/202305/1936833-20230515235422303-2133238037.png
此处插入题外话,笔者发现CI执行每个e2e的测试文件的次序是固定的,走到generateCode的下一个e2e测试任务就马上会遇到该问题,以至于笔者一直以为是任务A出了问题,但本地单独jest该任务永远都是Pass的,致使笔者一度有些...
但是经过前辈的指导,其中一个就是让笔者在本地使用CI所使用的命令,对所有e2e测试文件进行测试,而不是对单个e2e测试文件进行测试。同时,前辈让笔者留意是否与DB之间的连接关闭之后仍然有着读写DB的操作。
也就是说:
# 用这个
yarn jest tests/e2e

# 而不是用这个
yarn jest tests/e2e/generate_code_for_person.ts得益于本地运行命令,笔者发现测试文件的执行顺序并不是固定的,自然而然地发现每一个跟在generateCode的后e2e测试任务就会QueryFailedError。于是进行了注释debug方法,也就是每个describe都注释一下,最后锁定了问题出在generateCode函数中。
由此,笔者悻悻地将代码给改了,给controllers/personController.ts中加了一个utils.runInBackground。
也就是:
// 处理逻辑的controllers中,eg: controllers/personController.ts
async function generateCodeForPerson(ctx, next): Promise<void> {
    const person = await getPerson(ctx.params.id);
    utils.runInBackGround(async () => {
      await generateCode(person); // 这里做不做await好像都没所谓了。
    });
    ctx.code = 200;
}于是乎就这么改了,CI就过了。
所以后续会继续记录在进行和使用jest、postgres sql、typeorm、数据库表设计过程中的的所见所闻。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: QueryFailedError: Connection Terminated