Coroutine 예외 처리 3편 - Supervision - SupervisorJob, SupervisionScope 사용해 예외 처리하기

2023. 5. 13. 15:35·공식 문서 번역/Coroutines 공식 문서
반응형

Supervision

이전에 공부한 것처럼, 취소는 Coroutine의 전체 계층을 통해 전파되는 양방향 관계를 가진다.*1 단방향 취소만이 필요한 경우를 살펴보자.

 

이러한 요구사항에 대한 좋은 예제는 Scope 내부에 Job이 선언된 UI 구성요소이다. 만약 UI의 자식의 작업이 실패되더라도, 언제나 모든 UI 구성요소를 취소(효과적으로 종료)하는 것은 필수적이지 않다. 하지만, UI 구성요소가 파괴되면(그리고 그 Job이 취소되면), 더이상 결과값이 필요 없기 때문에 모든 자식 Job을 취소하는 것은 필수적이다. 

 

다른 예시는 여러 자식 Job을 생성하고 이들의 실행이 감독*2되고 그들의 실패가 추적되어서 실패된 것들만 재시작 해야하는 서버 프로세스이다. 

 

Supervision job

SupervisorJob이 이 복적을 위해 사용될 수 있다. 이는 취소가 아래 방향으로 전파되는 것만 제외하면 일반적인 Job과 비슷하다. 이는 다음 예제를 통해 설명될 수 있다.

 

val supervisor = SupervisorJob()
with(CoroutineScope(coroutineContext + supervisor)) {
    // launch the first child -- its exception is ignored for this example (don't do this in practice!)
    val firstChild = launch(CoroutineExceptionHandler { _, _ ->  }) {
        println("The first child is failing")
        throw AssertionError("The first child is cancelled")
    }
    // launch the second child
    val secondChild = launch {
        firstChild.join()
        // Cancellation of the first child is not propagated to the second child
        println("The first child is cancelled: ${firstChild.isCancelled}, but the second one is still active")
        try {
            delay(Long.MAX_VALUE)
        } finally {
            // But cancellation of the supervisor is propagated
            println("The second child is cancelled because the supervisor was cancelled")
        }
    }
    // wait until the first child fails & completes
    firstChild.join()
    println("Cancelling the supervisor")
    supervisor.cancel()
    secondChild.join()
}

📌 전체 코드는 이곳에서 확인할 수 있습니다.

 

이 코드의 출력은 다음과 같다 :

The first child is failing
The first child is cancelled: true, but the second one is still active
Cancelling the supervisor
The second child is cancelled because the supervisor was cancelled

 

Supervision Scope

특정 범위에 대한 동시성을 적용하기 위해 coroutineScope 대신 supervisorScope을 사용할 수 있다. 이는 취소를 한 방향으로만 전파하며, 그 자신이 실패했을 때만 자식 Coroutine들을 취소한다. 또한 coroutineScope 처럼 완료되기 전에 모든 자식들이 완료되는 것을 기다린다.

try {
    supervisorScope {
        val child = launch {
            try {
                println("The child is sleeping")
                delay(Long.MAX_VALUE)
            } finally {
                println("The child is cancelled")
            }
        }
        // Give our child a chance to execute and print using yield 
        yield()
        println("Throwing an exception from the scope")
        throw AssertionError()
    }
} catch(e: AssertionError) {
    println("Caught an assertion error")
}

📌 전체 코드는 이곳에서 확인할 수 있습니다.

 

이 코드의 출력은 다음과 같다 :

The child is sleeping
Throwing an exception from the scope
The child is cancelled
Caught an assertion error

 

Supervise가 사용된  Coroutine에서의 예외

Job과 SupervisorJob의 또다른 중요한 차이는 예외 처리이다. 모든 자식은 자신의 예외를 예외 처리 메커지니즘에 따라 직접 처리해야 한다. 이 다른점은 자식의 실패가 부모에게 전파되지 않는다는 점이다. 이는 supervisorScope 내부에서 직접 실행된 Coroutine은 root Coroutine과 비슷하게 그들의 Scope내부에 설치된 CoroutineExceptionHandler를 쓰는 것을 뜻한다.(자세한 것은 CoroutineExceptionHandler 섹션을 참조)  

 

val handler = CoroutineExceptionHandler { _, exception -> 
    println("CoroutineExceptionHandler got $exception") 
}
supervisorScope {
    val child = launch(handler) {
        println("The child throws an exception")
        throw AssertionError()
    }
    println("The scope is completing")
}
println("The scope is completed")

📌 전체 코드는 이곳에서 확인할 수 있습니다.

 

이 코드의 출력은 다음과 같다 :

The scope is completing
The child throws an exception
CoroutineExceptionHandler got java.lang.AssertionError
The scope is completed

 


📖 아래 내용은 독자의 이해를 위해 번역자가 추가한 글입니다.

*1. 자식 Coroutine에서 취소가 발생하면 부모 Coroutine으로 전파되며, 부모 Coroutine에게 다른 자식 Coroutine이 있다면 해당 자식 Coroutine 들도 취소된다. 

*2. supervise의 뜻이 감독이다.

 


이 글은 Coroutines 공식 문서를 번역한 글입니다.

 

원문 : Coroutine exceptions handling - Supervision

원문 최종 수정 :  2022년 6월 27일

 


 

반응형

'공식 문서 번역 > Coroutines 공식 문서' 카테고리의 다른 글

Coroutine 공유 상태와 동시성 2편 - Thread-safe한 데이터 구조, 세밀하게 Thread 제한하기, 굵게 Thread 제어하기  (0) 2023.05.15
Coroutine 공유 상태와 동시성 1편 - Coroutine을 여러개 실행했을 때의 문제점, Volatile은 동시성 문제를 해결하지 못한다.  (0) 2023.05.14
Coroutine 예외 처리 2편 - Cancellation과 Exceptions, Exceptions 합치기  (0) 2023.05.12
Coroutine 예외 처리 1편 - Exception 전파, CoroutineExceptionHandler 사용해 전파된 예외 처리하기  (0) 2023.05.11
Coroutine Channels 4편 - Buffered channels, Channel은 평등하다, Ticker channels  (0) 2023.03.08


'공식 문서 번역/Coroutines 공식 문서' 카테고리의 다른 글
  • Coroutine 공유 상태와 동시성 2편 - Thread-safe한 데이터 구조, 세밀하게 Thread 제한하기, 굵게 Thread 제어하기
  • Coroutine 공유 상태와 동시성 1편 - Coroutine을 여러개 실행했을 때의 문제점, Volatile은 동시성 문제를 해결하지 못한다.
  • Coroutine 예외 처리 2편 - Cancellation과 Exceptions, Exceptions 합치기
  • Coroutine 예외 처리 1편 - Exception 전파, CoroutineExceptionHandler 사용해 전파된 예외 처리하기
심플코드
심플코드
프로그래밍을 어렵지 않게 풀어서 설명하는 기술 블로그
    반응형
  • 심플코드
    심플코드
    심플코드
  • 전체
    오늘
    어제
    • 분류 전체보기 (96)
      • 안드로이드를 위한 Coroutines (2)
      • Unit Testing (19)
      • GitHub Actions (0)
      • 공식 문서 번역 (35)
        • Coroutines 공식 문서 (35)
      • 알고리즘 (7)
        • Kotlin 자료구조 (0)
        • 알고리즘 (7)
        • Kotlin으로 구현하는 자료구조 (0)
      • 코딩 테스트 (0)
      • Deep Learning (0)
      • Machine Learning Math (17)
        • Linear Algebra (17)
      • ML (0)
      • Docker (15)
      • Kubernetes (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

    • 코틀린 코루틴의 정석 책 출간 소식
  • 인기 글

  • 태그

    Coroutines Context
    TensorFlow
    unit testing
    Machine Learning
    Docker
    pytorch
    컨테이너
    coroutine
    Coroutines Channel
    mockito
    Coroutines
    junit
    Kotlin
    Coroutines Flow
    코루틴 채널
    unit test
    numpy
    코루틴
    도커
    코루틴 Flow
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
심플코드
Coroutine 예외 처리 3편 - Supervision - SupervisorJob, SupervisionScope 사용해 예외 처리하기
상단으로

티스토리툴바