문제 발생
‘어느날 갑자기’ Jenkins 배포중 빌드가 실패, Jenkins 실패 원인을 보니 테스트가 깨지고 있었음
현상 재현을 위해 로컬에서 테스트를 돌렸으나 모든 테스트는 Pass
Jenkins의 간헐적 이슈 인가 싶어 다시 Jenkins 빌드를 진행하니 성공후 정상 배포되었음
(이때까지만 해도 Jenkins의 버그로 인한 단순 해프닝으로 생각)
2주뒤 다시 정기배포일자가 다가왔고, 배포를 진행했으나 이전과 동일하게 다시 Jenkins 빌드가 실패함
로컬에서도 마찬가지로 테스트가 깨지고 있었고 로그에서는 아래와 같이 Atomikos 에러가 출력
수 차례 재시도 하니 정상적으로 배포됨...
나를 더욱 헷갈리게 하는 상황들
- Jenkins 배포시에도 매번 실패하는 것이 아닌 여러번 시도하면 그 중 한번은 성공함
- 로컬에서도 테스트가 실패할때도 있고, 실패하지 않을때도 있으며 실패하는 테스트 케이스가 매번 바뀜
삽질 시작
테스트의 신뢰성이 깨진 상태이며, 배포시에도 테스트코드로 인한 검증이 정상적으로 진행되지 않고 배포되고 있는 상황이기에 빠른 조치가 필요했음
가설 1.
gradle test는 테스트 순서가 매번 고정적이지 않고, 테스트시마다 테스트의 순서가 다르다는것을 확인
- gradle test는 테스트의 순서를 보장하지 않으며, 병렬로 실행된다. 이로 인해 테스트 실행 순서를 예측할 수 없게 만든다.
- gradle test는 실패한 테스트를 먼저 수행함
우리 팀에서는 많은 테스트 케이스가 ‘통합 테스트’ 기반으로 작성되어 있었으며, 통합테스트의 특성상 서로간의 테스트에 영향을 주어 테스트 순서에 따라 테스트가 실패할 수 있을것으로 의심
→ 통합 테스트 케이스별 사전에 세팅된 DB 데이터를 검수하여 충돌지점을 모두 찾아보았으나, 데이터 충돌이 의심되는 부분이 없었음, 더불어 현재 테스트 실패의 원인은 DB 커넥션 풀에 중복된 이름의 커넥션이 생기는 에러이기에 해당 가설은 해당사항이 없음.
가설 2. (원인)
Spring Event를 이용한 비동기 로직으로 인해, 테스트 종료시에도 비동기 로직이 동작함으로 커넥션풀이 정리되지 못하여 발생
Junit 테스트에서 통합테스트는 앞선 통합테스트가 종료되어야만 이후 테스트가 진행된다. 앞선 테스트 케이스가 종료됐다고 판단되어(비동기 로직은 동작중) 이후 테스트 케이스가 동작하며 새로운 커넥션 을 생성하여 풀에 등록하려 하였으나, 앞선 비동기 로직에서 사용중인 커넥션과 동일한 이름의 커넥션이 충돌하여 발생한 이슈
해결
Profile별 Spring Event Listener를 분리하여 test시에는 Mock처리된 비동기 로직이 동작되도록 처리 (로컬 혹은 테스트환경에서 동작하지 않아도 되기때문에 위와 같이 처리, 비동기 로직이 로컬에서도 검증되어야 한다면 countDownLatch와 같이 비동기 로직의 실행을 검증할 수 있는 방법을 사용해야 한다.)
삽질하는 과정에서는 너무 어렵고 고통스러웠는데, 막상 해결하고나니 너무 당연한 이슈..
'Spring' 카테고리의 다른 글
[Spring] 카카오 로그인 REST API 방식 적용 및 구현 (0) | 2024.11.26 |
---|---|
[Spring] 스프링 부트(Spring Boot) - H2 DB 연동하여 사용하기(with.JPA) (0) | 2024.11.22 |
IntelliJ에서 Spring MVC 세팅하기 (0) | 2024.03.17 |
[Spring] Spring Boot 3 마이그레이션 시작하기 (0) | 2023.12.13 |
[JPA] 일대다(1:N), 다대일(N:1) 관계 (0) | 2023.09.03 |