我们在TypeORM方面遇到了奇怪的问题,特别是在Jest中(可能有关系,也可能不是)。某个测试完全卡住了,我们很难找出问题所在。
在技术栈方面,使用了Typescript、NodeJS、Apollo Graphql、Jest和MySQL。实际上,有问题的测试是使用Apollo的集成测试框架的一个集成测试。
首先发生的是,一个特定的测试完全卡住了,在几分钟后控制台抛出了错误:
最初,我将其从
这是在试图找出发生了什么事情后,通过调整
这个方法有效了一会儿,但现在看起来测试又卡住了(测试用例没有变化,但被测试的代码 已经 变化)。现在在测试挂起后,我们会得到这个错误:
我们发现这是导致测试卡住的事件顺序:
我们还注意到以下情况:
如果我们确保只在更新时使用 queryRunner,而不是在查询时使用,则死锁就不会发生。
更改代码使得我们先使用常规连接对象进行所有读取查询(而不是 queryRunner),然后如果我们连接到 queryRunner 并进行所有写操作,则死锁不会发生。
有没有人能够解释一下可能发生了什么?在使用 queryRunner 时是否存在某些不稳定性或需要考虑的特殊事项?
谢谢!
在技术栈方面,使用了Typescript、NodeJS、Apollo Graphql、Jest和MySQL。实际上,有问题的测试是使用Apollo的集成测试框架的一个集成测试。
首先发生的是,一个特定的测试完全卡住了,在几分钟后控制台抛出了错误:
QueryFailedError: ER_LOCK_WAIT_TIMEOUT: Lock wait timeout exceeded; try restarting transaction
试图确定问题的原因,我找到了我们在afterEach
上运行的一个函数,它"销毁"数据库。最初运行的代码如下:await queryRunner.query('DELETE FROM Table1');
await queryRunner.query('DELETE FROM Table2');
...
最初,我将其从
queryRunner
更改为queryBuilder
后,错误和“死锁”问题得到了修复。await queryBuilder.delete().from('Table1').execute();
...
这是在试图找出发生了什么事情后,通过调整
SHOW PROCESSLIST;
和 SHOW ENGINE InnoDB STATUS;
来完成的。我还将事务隔离级别更改为 READ-COMMITTED,但并没有用。除了将其从queryRunner
更改为queryBuilder
之外,没有任何方法真正起作用。这个方法有效了一会儿,但现在看起来测试又卡住了(测试用例没有变化,但被测试的代码 已经 变化)。现在在测试挂起后,我们会得到这个错误:
Error: Pool is closed
。之后测试就被“释放”,所有的测试一个接一个地失败了。我们发现这是导致测试卡住的事件顺序:
1. open a transaction with queryRunner
2. perform a read query
3. then perform a write
4. commit the transaction and release the queryRunner
5. delete the DB
6. perform a write - deadlock
我们还注意到以下情况:
如果我们确保只在更新时使用 queryRunner,而不是在查询时使用,则死锁就不会发生。
更改代码使得我们先使用常规连接对象进行所有读取查询(而不是 queryRunner),然后如果我们连接到 queryRunner 并进行所有写操作,则死锁不会发生。
有没有人能够解释一下可能发生了什么?在使用 queryRunner 时是否存在某些不稳定性或需要考虑的特殊事项?
谢谢!
async/await
有任何关系。 - Sagi Rikaawait
关键字。因此,在函数执行实际结束之前,连接就被关闭了。 - WhiteAngel