Coroutine을 사용하다보면 join과 await를 마주치게 됩니다. 둘 다 작업이 끝날 때까지 기다린다는 공통점을 가치고 있지만, 의미와 사용 목적은 명확히 다릅니다.
이번 글에서는 join과 await의 정의, 차이점, 그리고 언제 무엇을 써야 하는지 정리해보겠습니다.
SupervisorJob은 자식 코루틴 간의 실패를 서로 전파하지 않는 Job입니다.
val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
scope.launch {
launch {
error("실패")
}
launch {
delay(1000)
println("정상 실행")
}
}
위 코드에서는 첫 번째 코루틴이 실패하더라도 두 번째 코루틴은 정상적으로 실행됩니다. SupervisorJob은 독립적인 작업들을 한 스코프에서 관리하고 싶을 때 유용합니다.
supervisorScope는 SupervisorJob을 사용하는 suspend 함수 기반 스코프 빌더입니다.
suspend fun loadData() = supervisorScope {
launch {
error("실패")
}
launch {
delay(1000)
println("정상 실행")
}
}
여기서 첫 번째 코루틴이 실패해도 두 번째 코루틴은 취소되지 않습니다. supervisorScope는 일시적으로 실패 격리가 필요한 경우에 적합합니다.
하나의 실패가 모든 코루틴을 망치게 둘 것인가, 아니면 독립적으로 관리할 것인가?
이 질문에 대한 답이 바로 Supervisor의 존재 이유입니다.
코루틴을 잘 쓰기 위한 핵심은 동시성보다 실패를 어떻게 다룰 것인가를 설계하는 것입니다. SupervisorJob과 supervisorScope를 이해하면, 코루틴 에러 처리의 시야가 한 단계 넓어질 것입니다.