본문 바로가기

Kotlin

[Kotlin] Coroutine (3) - 예외 처리

 

안녕하세요.

코루틴 예외 처리에 대해 알아보겠습니다.


사전 지식

코루틴에서 예외 처리는 기존의 예외 처리와는 조금 다른 방식으로 처리합니다.

코루틴은 비동기적으로 동작하고 여러 스레드 간에 분산되어 있을 수 있기 때문에 몇 가지 고려할 사항이 있습니다.

 

코루틴 구조

코루틴은 계층 구조를 가집니다.

호출한 코루틴은 자식 코루틴이 됩니다.

 

예외 전파

예외가 발생하면 기본적으로 부모로 전파하게 됩니다.

 

예외가 발생하면 해당 코루틴은 물론, 자식 코루틴의 작업이 전부 cancel 됩니다.

 

job5에서 예외가 발생하면 job2 -> job1 까지 예외가 전파됩니다.

⇒ 최종적으로 job1을 루트로 하는 subtree 내의 모든 코루틴의 실행이 취소됩니다.


예외 처리 방법

try-catch

launch 안의 코드에서 에러를 처리할 때 사용할 수 있습니다.

import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

suspend fun routineA() {
    delay(100L)
    error("cancel")
}

suspend fun routineB() {
    delay(200L)
    println("routineB end")
}

fun main(): Unit = runBlocking {
    launch {
        try {
            routineA()
            routineB()
        } catch (e: Exception) {
            println("coroutine failed")
        }
    }
}
coroutine failed

 

하지만, launch 자체에서 예외가 발생할 때 제대로 처리하지 못합니다.

import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

suspend fun routineA() {
    delay(100L)
    error("cancel")
}

suspend fun routineB() {
    delay(200L)
    println("routineB end")
}

fun main(): Unit = runBlocking {
    try {
        launch {
            routineA()
            routineB()
        }
    } catch (e: Exception) {
        println("coroutine failed")
    }
}

 

⇒ launch 함수는 코루틴을 시작하고 바로 반환하며, 외부 try-catch 에서는 코루틴의 실행 상태를 기다리지 않기 때문에 생기는 문제입니다.


CoroutineExceptionHandler

예외가 발생했을 때 특정 동작을 정의할 수 있습니다.

해당 코루틴 scope에서 발생하는 에러를 일괄적으로 처리할 수 있습니다.

import kotlinx.coroutines.*

suspend fun routineA() {
    delay(100L)
    error("cancel")
}

suspend fun routineB() {
    delay(200L)
    println("routineB end")
}

fun main(): Unit = runBlocking {
    val exceptionHandler = CoroutineExceptionHandler { _, exception ->
        println("Caught exception: $exception")
    }

    val job = CoroutineScope(Dispatchers.Default + exceptionHandler).launch {
        routineA()
        routineB()
    }

    job.join()
}
Caught exception: java.lang.IllegalStateException: cancel

SupervisorScope

자식 코루틴 중 하나에서 예외가 발생해도 다른 자식 코루틴에는 영향을 미치지 않도록 할 수 있습니다.

 

SupervisorScope을 사용하면, 자식 Coroutine에서 발생한 예외를 부모 Coroutine으로 전파하지 않습니다.

import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.supervisorScope

suspend fun routineA() {
    delay(100L)
    error("cancel")
}

suspend fun routineB() {
    delay(200L)
    println("routineB end")
}

fun main(): Unit = runBlocking {
    supervisorScope {
        launch {
            routineA()
        }

        launch {
            routineB()
        }
    }
}

 

부모로 예외가 전파되지 않습니다.

→ 형제 코루틴의 실행이 cancel 되지 않고 무사히 완료할 수 있습니다.


Reference

[Kotlin] Coroutine - 4. 코루틴에서의 예외(exception) 핸들링

 

[Kotlin] Coroutine - 4. 코루틴에서의 예외(exception) 핸들링

Coroutine 안녕하세요~ 오늘은 Coroutine 을 구현할 때 예외 처리에 대한 방법을 알아보도록 해볼려고 해요 흔히들 kotlin 에서는 try catch 문을 활용해서 예외를 핸들링 하거나 runCatching 문을 통해서 Resul

huisam.tistory.com

 

Coroutine 에서의 Error handling

 

Coroutine 에서의 Error handling

코루틴에서의 예외처리를 한번 살펴봅니다.

co-zi.medium.com

 

'Kotlin' 카테고리의 다른 글

[Kotlin] Extension Function (확장 함수)  (0) 2024.09.10
[Kotlin] Null Safety  (0) 2024.07.29
[Kotlin] Coroutine (2) - Use in Kotlin  (0) 2023.11.30
[Kotlin] Coroutine (1) - 코루틴이란?  (0) 2023.11.30