Loop를 돌면서 Transaction 처리를 하는 로직이 있다. 여기에 추가적인 로직이 들어가야하는데, 문제는 외부 API를 호출해야하는 로직이 포함되어있다.
Loop를 통해 영속화된 데이터를 기반으로 API 호출이 필요한 상황인데, 그냥 가벼운 생각으로 로직 중간중간 마다 API 호출을 시도하고, 호출 결과를 다시 업데이트 해줄 생각으로 작업을 시작했다. 하지만 그 생각이 고통의 길로 이끌줄은 몰랐다.(여전히 진행중)
일단, 트렌젝션 중간에 API 호출을 한다? 이거부터 다시 생각을 해볼 필요가 있을거 같다. 보기만해도 안티패턴 같은데, 왜 그럴까?
트랜잭션을 사용하는 이유는 데이터 정합성을 위함이다. 다수의 요청이 들어왔을 때 DBMS는 그 순서를 정확하게 보장할 수 없다. 그럴 경우, 데이터의 정확성에 문제가 생김. 이 때 논리적으로 한 번에 처리될 필요가 있는 하나 이상의 쿼리를 단일 작업으로 묶어 데이터 정합성을 확보한다.
트랜잭션에 묶인 작업 단위는 모두 실행되어야 한다. 트랜잭션 처리 과정 중 문제가 생긴다면, 이전상태로 롤백한다. 이를 위해 DBMS는 이전 상태를 저장해놓는데, 이전상태를 저장하는 임시 영역을 롤백 세그먼트라고 한다.
트랜잭션의 일관성 보장은, 테이블에 이벤트에 자동으로 반응하는 트리거(Trigger)를 통해 보장하는데, 이 트리거는 해당 작업 전・후에 모든 제약조건과 만족하는지 확인하여 일관성을 유지한다.
트랜잭션은 서로 영향울 주면 안된다. 트랜잭션 작업 중 다른 트랜잭션이 끼어들지 못하도록 보장해야 한다.
트랜잭션은 공통된 데이터를 동시 처리하는 과정에서 갱신분실, 오손판독, 반복불가능, 팬텀문제등 여러 문제가 발생할 수 있다.
DBMS는 Lock & excute unlock을 통해 고립성을 보장한다
트랜잭션이 성공(Commit)하면 하드웨어 혹은 소프트웨어 오류등 어떤 이유로도 그 결과가 유실 되서는 안되고 영원히 보장되어야 한다. 트랜잭션이 성공하면, 트랜잭션에 대한 로그가 남아있어야 한다.
API호출은 언제나 실패 가능성이 있다. 호출 결과를 가지고 DB 작업을 해야되는 상황이라면, 안정적으로 데이터를 처리하는것에 영향을 줄 수 있다(외부요인으로). 게다가 트랜잭션 사용중에는 락이 걸리기때문에 서비스 전체적으로 영향이 갈 수 있다. API 호출이 너무 오래걸릴 경우, 이러한 부분도 충분히 문제가 될 수 있겠다 싶음.
일단, 원자성이 깨진다? 원자성이 너무쉽게 깨진다?고 생각하는걸로 하고, 다시 공부해야지
다음은 GPT의 대답이다
트랜잭션 시간 증가: 트랜잭션은 데이터베이스 리소스를 잠금 상태로 유지합니다. 외부 API 호출은 네트워크 상태와 응답 시간에 따라 다를 수 있으므로 트랜잭션 시간이 불필요하게 길어질 수 있습니다. 이는 데이터베이스 리소스의 비효율적인 사용으로 이어질 수 있습니다.
트랜잭션 롤백의 어려움: 외부 API 호출은 트랜잭션과 독립적으로 수행됩니다. 만약 트랜잭션이 실패하여 롤백되더라도, 이미 수행된 API 호출을 취소하거나 되돌릴 방법이 없습니다. 이는 데이터 일관성 문제를 초래할 수 있습니다.
신뢰성 문제: 외부 API는 다양한 이유로 실패할 수 있습니다 (예: 네트워크 문제, 서버 다운타임). 트랜잭션 내에서 이러한 실패를 처리하는 것은 복잡성을 증가시키고, 트랜잭션의 신뢰성을 낮출 수 있습니다.
TypeORM을 사용하고 있는데, 작업중 발생한 에러이다. 이 에러의 원인은 뭘까?
typeORM githiub이슈에 올라온 글을 보면
I found the solution, might be useful for anyone : when using transaction, you mustn't mix up save and find queries with the transaction manager. Otherwise, i suppose mysql doesn't know what to rollback, therefore it just commits everything. So just use the repository manager for find requests, and use the queryRunner.manager or transactionManager only for saving the transaction entities.
트랜잭션 관리자와 save, find와 같은 쿼리를 섞어서 생기는 문제? typeorm 문서에도
트랜잭션에서 작업할 때 가장 중요한 제한 사항은 제공된 엔티티 관리자 인스턴스를 항상 transactionalEntityManager 사용해야 한다는 것입니다 . 이 예에서는 GLOBAL ENTITY MANAGER를 사용하지 마십시오. 모든 작업은 제공된 트랜잭션 엔티티 관리자를 사용하여 실행 해야 합니다.
결국 내 로직 내에서 quneryRunner.manager를 사용하지 않는 부분이 있다는걸까? 일단 의심가는 부분은 외부
이렇게해도 안된다면...다른 방법을 시도해야지 아자자