-
코루틴 예외 처리: supervisorScope를 활용한 문제 해결📖 개발 공부/kotlin 2025. 1. 19. 15:16
후기 작성 이벤트 코드를 개발하던 중, 코루틴의 예외 처리로 인해 테스트 코드가 실패하는 문제가 발생했다.
특정 유저가 이벤트 대상자인지 확인하는 로직에 코루틴이 적용되어 있었고, 다음과 같은 조건들을 비동기로 검증하고 있었다.
- 이미 해당 업체에 후기를 작성했는지
- 유효한 사용자인지
- 이벤트 예산을 초과했는지
문제 상황
유효한 사용자인지 확인하는 조건은 다음과 같은 코드를 통해 검증하고 있었다.
return runBlocking { val validUserDeferred = async(Dispatchers.IO) { checkValidUser(userId) } try { validUserDeferred.await() } catch (e: UserRestException) { return Response( isEligible = false, reason = INVALID_USER, ) } // ... }
테스트 코드를 실행했을 때, checkValidUser 메서드에서 예외가 발생하면 try-catch 블록을 통해 Response를 반환하도록 작성했음에도 불구하고, 기대한 대로 동작하지 않았다.
예외가 부모 코루틴까지 전파되면서 부모 코루틴이 취소되어 테스트가 실패한 것이다.
다음과 같은 상황이라고 이해하면 좋을 것 같다.
코루틴 예외 전파 방식
코루틴은 기본적으로 coroutineScope를 사용하며, 자식 코루틴 중 하나에서 예외가 발생하면 부모 코루틴과 다른 자식 코루틴들도 모두 취소된다.
이러한 동작은 안정성을 위해 설계된 것이지만, 이번 상황에서는 특정 작업의 예외를 다른 작업에 영향을 미치지 않도록 처리할 필요가 있었다.
임시방편 해결
처음에는 runBlocking 블록을 try-catch로 감싸 예외를 처리했으나, 이 방식은 문제를 근본적으로 해결하지 못했다.
예외 처리 로직이 특정 코루틴 블록 내에서만 이뤄져야 하는데, 외부로 노출되면서 가독성과 유지보수성이 떨어졌다.
어떤 작업에서 예외가 발생했는지 확인하려면 내부 코드를 일일이 확인해야 했다.
sususu…supervisorScope 발견!
문제를 해결하기 위해 코루틴 예외 처리 방식에 대해 조사하던 중, supervisorScope라는 스코프를 알게 되었다.
- coroutineScope: 자식 코루틴 중 하나라도 실패하면 부모와 다른 자식 코루틴도 모두 취소된다.
- supervisorScope: 자식 코루틴 중 하나가 실패하더라도 다른 자식 코루틴에는 영향을 미치지 않는다.
즉, supervisorScope는 부모 코루틴으로 예외가 전파되지 않도록 해준다.
수정된 코드
supervisorScope를 적용한 코드는 아래와 같다.
return runBlocking { supervisorScope { val validUserDeferred = async(Dispatchers.IO) { checkValidUser(userId) } try { validUserDeferred.await() } catch (e: UserRestException) { return@supervisorScope Response( isEligible = false, reason = INVALID_USER, ) } // ... }
이제 예외가 발생해도 해당 작업만 독립적으로 실패하며, 부모 코루틴과 다른 작업은 영향을 받지 않는다.
결과
코드를 수정한 후 테스트 코드가 성공적으로 실행되었으며, 예외 발생 시의 동작도 기대한 대로 동작했다. 아래 그림처럼 supervisorScope를 통해 예외가 전파되지 않도록 처리했다.
코루틴 예외 처리 방식에 대한 이해를 높이고, 적절한 스코프를 선택하여 가독성과 유지보수성을 개선할 수 있었다.
비슷한 이슈를 겪는 분들에게 이 글이 도움이 되길 바란다!
참고 자료
코루틴의 예외 처리 방식에 대해 더 자세히 알고 싶다면 카카오페이 기술 블로그를 참고해보길 권한다.
다양한 예외 처리 방식이 그림과 함께 설명되어 있어 이해하는 데 큰 도움이 된다. 위 상황과 비슷한 이슈를 겪으신 분들이 한번씩 보시면 좋을 것 같다~
반응형'📖 개발 공부 > kotlin' 카테고리의 다른 글
테스트 코드 개선하기: Kotest 모킹 초기화 및 구조 개선 (0) 2024.10.27 Kotlin의 Value Class로 성능 최적화하기 (Codes like a class, works like an int.) (0) 2024.10.07 Spring AOP를 Kotlin으로 개선해보기! (feat. 카카오페이 테크블로그) (0) 2024.03.17 Kotest 예제와 함께 테스트 코드 살펴보기 (0) 2024.02.04 도메인 모델에 kotlin의 data class가 적합할까? (0) 2023.12.10