API 호출이 오래걸릴 때

유석현(SeokHyun Yu)·2022년 7월 12일
0

문제 해결

목록 보기
2/11

문제 발생

한 api가 transaction을 통해 데이터를 갱신하거나 생성하는 api일 때, 코드에서

const queryRunner = await getConnection().createQueryRunner();
await queryRunner.startTransaction();

위와 같이 쿼리 빌더를 통해 트랜잭션을 시작하고 각종 repository에서 함수를 가져와 실행하였다.

오늘도 api를 열심히 수정하고 postman을 통해 호출하는데

호출이 계속 지연되면서 결국 위와 같이 status code가 500이 뜨는 상황이 발생했다.


문제 해결

분명 로직은 잘못된게 없을텐데 하고 콘솔을 봤더니 처음에 트랜잭션이 실행되고 콘솔창에 찍히는 "START TRANSACTION" 이후에 또 "START TRANSACTION"이 찍히는 것이었다.

그래서 트랜잭션이 일어나는 함수를 자세히 살펴보았더니..

// sampleService
  async updateSample(...): Promise<void> {
    const queryRunner = await getConnection().createQueryRunner();
    await queryRunner.startTransaction();

    try {
       await this.sample2Repository.saveSample2({
            ...
          });
         
       await this.sample3Repository.saveSample3(queryRunner.manager, {
           ...
          });

      await queryRunner.commitTransaction();
    } catch (e) {
      await queryRunner.rollbackTransaction();
      
      throw e;
    } finally {
      await queryRunner.release();
    }
  }
// sample2Repository
async saveSample2(...): Promise<void> {
    const data = this.create(...);

    await this.save(data, { reload: false });
}
// sample3Repository
  async saveSample3(
    transactionManager: EntityManager,
    ...
  ): Promise<void> {
    if (!transactionManager) throw new Error();

    const data = this.create();

    ...

    await transactionManager.save(Sample3, data);
  }

saveSample2 함수와 saveSample3 함수의 차이가 보이는가? 🧐

saveSample3 함수는 updateSample 함수에서 생성한 queryRunner를 인자로 받아 transactionManager.save() 로 DB에 데이터를 저장하고 있지만, saveSample2 함수는 그냥 함수 자체에서 this.save() 를 통해 저장하고 있다.

그렇게 되면 updateSample 에서 트랜잭션을 시작해도 saveSample2 까지 트랜잭션이 이어지지가 않고 saveSample2 에서 트랜잭션이 새로 시작되어 오류가 발생하는 것이었다.

따라서, 한 함수에서 트랜잭션을 시작하고 나면 그 함수가 끝날 때까지 그 안에서 호출되는 (db를 건드리게 되는)함수들은 모두 이미 생성된 EntityManager(transactionManager) 를 인자로 받아 save 해야 한다.(delete, update도 마찬가지일 듯 하다)

profile
Backend Engineer

0개의 댓글