연주 분석에는 트랜잭션이 끝나는 시점이 중요한 일이 두 가지 있습니다. 분석 결과를 기록할 때는 세션 상태와 평가를 함께 저장합니다. 녹음이 올라왔을 때는 업로드가 확정된 뒤에만 분석을 시작합니다. 둘 다 오류를 던지는지만 확인하면, 앞서 실행한 쓰기나 바깥에 넘긴 작업이 남았는지 알 수 없습니다.

롤백 뒤 남은 DB 상태 확인

보통 매퍼 테스트는 테스트에 트랜잭션을 열어 두고 끝에서 한꺼번에 되돌립니다. 결과 저장의 원자성 검사에서는 테스트 트랜잭션을 열지 않았습니다. 테스트가 서비스 트랜잭션의 커밋 경계를 대신하면, 서비스를 벗어난 뒤에도 무엇이 남는지 구분하기 어렵기 때문입니다.

임시 MySQL에 PENDING 세션을 준비한 뒤, 참조할 수 없는 음높이 ID를 가진 음표 결과를 저장하도록 했습니다. 이 경로에서는 세션을 완료로 바꾸고 평가를 삽입한 뒤 음표 결과를 넣습니다. 마지막 단계에서 데이터 접근 예외가 난 다음 DB를 읽으니 세션은 PENDING이었고 평가 행은 0개였습니다. 테스트가 만든 행은 검사가 끝난 뒤 외래 키 순서를 따라 직접 지웠습니다.

갱신 성공 시 이벤트 한 건

업로드를 처음 설계할 때는 저장이 끝나면 호출할 콜백 인터페이스를 두었습니다. 분석 쪽에서 커밋 후에 이벤트를 받는 구현을 먼저 병합하면서, 업로드도 그 계약에 맞춰 같은 이벤트를 발행하도록 바꿨습니다. 두 기능은 이벤트를 주고받고, 작업을 시작할 시점은 트랜잭션이 결정합니다.

업로드 저장소는 TransactionTemplate으로 DB 갱신과 이벤트 발행을 같은 트랜잭션 안에 두고, 실제로 1행을 바꿨을 때만 RecordingUploaded를 발행합니다. MySQL 매퍼 테스트에서는 다른 회원의 갱신, 소유자의 정상 갱신, 같은 세션의 두 번째 갱신을 차례로 시도했습니다. 소유자의 첫 갱신만 성공했고, @RecordApplicationEvents로 모은 업로드 이벤트도 한 건이었습니다.

이 기록은 발행 시점에 잡힙니다. 분석 리스너가 AFTER_COMMIT에서 실행되는지 확인하려면 트랜잭션이 끝난 뒤 작업에 넘긴 내역을 따로 봐야 합니다.

롤백·커밋 실패 뒤 분석 실행 여부

녹음 업로드 테스트에서는 이벤트를 발행한 뒤 분석에 넘긴 세션을 기록했습니다. 정상 커밋에서는 커밋을 마친 뒤 한 건을 넘겼고, 처음부터 롤백하도록 한 트랜잭션에서는 추가 작업이 없었습니다. 하지만 두 경우만으로는 커밋 직전에 실행하는 리스너와 커밋 직후 리스너를 구분하기 어렵습니다.

Spring의 트랜잭션 관리자 대역에 실제 커밋 단계에서 예외를 내는 분기를 추가했습니다. 커밋을 시도했다가 실패해도 분석에 넘어간 기록은 정상 요청의 한 건으로 유지됐습니다. 리스너를 BEFORE_COMMIT으로 바꿔 돌리면 실패한 업로드까지 목록에 들어와 그 검사가 실패했습니다.

결과 저장의 원자성은 DB에 남은 값으로, 업로드 이벤트는 발행 기록으로 확인했습니다. 커밋에 실패한 뒤 분석이 시작되지 않는지는 트랜잭션 관리자 대역으로 확인했습니다. 검사에서 만든 실패가 어느 단계에서 일어나는지에 따라 읽어야 할 기록도 달랐습니다.