0Pricing
Kotlin Academy · 강의

async/await 예외 전파

async에서 발생한 예외가 어떻게 전파되는지, 그리고 try-await를 언제 사용하는지 이해해 보세요.

async/await 예외 전파은(는) CoddyKit의 무료 Kotlin Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Kotlin Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Kotlin Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

async는 예외를 저장합니다

launch와 달리 async는 반환된 Deferred에 예외를 저장합니다. await()를 호출할 때만 예외가 다시 발생합니다.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val deferred = async {
        throw RuntimeException("async error")
    }
    try {
        deferred.await()  // exception rethrown here
    } catch (e: RuntimeException) {
        println("Caught: ${e.message}")
    }
}

await() 없이 발생한 예외

await()를 전혀 호출하지 않으면 일반 Job 부모에서는 예외가 조용히 버려집니다. supervisorScope와 항상 await하는 방식을 권장합니다.

import kotlinx.coroutines.*
fun main() = runBlocking {
    // Exception stored in deferred, never retrieved:
    val d = async { throw RuntimeException("lost exception") }
    delay(100)  // d has failed — exception never surfaced
    println("d.isCancelled: ${d.isCancelled}")
}

coroutineScope에서의 async

일반 coroutineScope에서 async 자식 작업이 예외를 발생시키고 그 예외가 전파되면, 즉 예외를 잡지 않으면 범위와 모든 형제 작업이 취소됩니다.

import kotlinx.coroutines.*
fun main() = runBlocking {
    try {
        coroutineScope {
            val a = async { "A" }
            val b = async { throw RuntimeException("B failed") }
            println(a.await())
            println(b.await())  // propagates, cancels scope
        }
    } catch (e: RuntimeException) {
        println("Scope failed: ${e.message}")
    }
}

supervisorScope에서의 async

supervisorScope에서는 async에서 발생한 예외가 형제 작업으로 전파되지 않습니다. 각 await()`는 개별적으로 감싸야 합니다.

import kotlinx.coroutines.*
fun main() = runBlocking {
    supervisorScope {
        val a = async { "A" }
        val b = async { throw RuntimeException("B failed") }
        println(a.await())
        try { println(b.await()) }
        catch (e: RuntimeException) { println("b failed: ${e.message}") }
    }
}

여러 async 작업에 awaitAll 사용

awaitAll(d1, d2, d3)은 모든 deferred를 기다립니다. 하나라도 실패하면 즉시 예외를 발생시키고 나머지를 취소합니다.

import kotlinx.coroutines.*
fun main() = runBlocking {
    try {
        val results = awaitAll(
            async { "result1" },
            async { throw RuntimeException("task 2 failed") },
            async { "result3" }
        )
        println(results)
    } catch (e: Exception) {
        println("awaitAll failed: ${e.message}")
    }
}

async와 runCatching

빠른 실패로 중단하지 않고 결과와 오류를 수집하려면 각 await()를 runCatching으로 감쌉니다.

import kotlinx.coroutines.*
fun main() = runBlocking {
    supervisorScope {
        val deferreds = listOf(
            async { "A" },
            async { throw RuntimeException("B") },
            async { "C" }
        )
        val results = deferreds.map { runCatching { it.await() } }
        results.forEach { println(it) }
    }
}

오류를 누적하는 병렬 작업

병렬 async 작업에서 발생한 모든 실패를 수집하여 빠르게 실패시키는 대신 함께 보고합니다.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val tasks = listOf("a", "b", "c")
    val results = supervisorScope {
        tasks.map { t ->
            async {
                if (t == "b") throw RuntimeException("b failed")
                t.uppercase()
            }
        }.map { runCatching { it.await() } }
    }
    val errors = results.filter { it.isFailure }
    val successes = results.mapNotNull { it.getOrNull() }
    println("Success: $successes, Errors: ${errors.size}")
}

예외 유형 보존

async 내부에서 발생한 예외는 유형이 보존됩니다. 정확하게 오류를 처리하려면 await()에서 구체적인 예외 유형을 포착합니다.

import kotlinx.coroutines.*
class NetworkException(msg: String) : RuntimeException(msg)
fun main() = runBlocking {
    val d = async { throw NetworkException("timeout") }
    try {
        d.await()
    } catch (e: NetworkException) {
        println("Network error: ${e.message}")
    } catch (e: Exception) {
        println("Other error: ${e.message}")
    }
}

일시 중단 없는 확인을 위한 Deferred.getCompleted()

join() 후에는 getCompleted()를 사용하여 결과를 동기적으로 가져옵니다. deferred가 실패했다면 예외가 발생합니다.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val d = async { 42 }
    d.join()  // wait without caring about result
    try {
        val result = d.getCompleted()  // synchronous — no suspend
        println("Result: $result")
    } catch (e: Exception) {
        println("Failed: ${e.message}")
    }
}

구조화된 동시성과 async

구조화된 동시성에서는 async deferred가 항상 부모 범위에 연결됩니다. 범위가 취소되면 deferred도 취소되므로 고아 작업이 남지 않습니다.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val scope = CoroutineScope(SupervisorJob())
    val d = scope.async {
        delay(1000)
        "result"
    }
    scope.cancel()  // cancels d too
    try { d.await() }
    catch (e: CancellationException) { println("Cancelled as expected") }
}

모범 사례: 항상 Await 사용

결과가 필요하지 않더라도 모든 async deferred에 항상 await()를 호출합니다. 그러면 예외가 드러나고 조용한 실패를 방지할 수 있습니다.

import kotlinx.coroutines.*
fun main() = runBlocking {
    supervisorScope {
        val d = async {
            // do background work
            "done"
        }
        // Always await:
        val result = runCatching { d.await() }
        println(result)
    }
}

빠른 확인

async { throw ... } 블록에서 발생한 예외는 언제 드러납니까?

복습

async는 예외를 Deferred에 저장하고, 예외는 await()에서 드러납니다. coroutineScope에서는 전파로 인해 형제 작업이 취소됩니다. supervisorScope에서는 각 await가 자체 실패를 처리해야 합니다. 모든 deferred에 항상 await를 호출합니다.

자주 묻는 질문

“async/await 예외 전파” 강의는 무료인가요?

네 — “async/await 예외 전파” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Kotlin Academy 강의 전체를 잠금 해제할 수 있습니다. Kotlin Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“async/await 예외 전파”에서 뭘 배우나요?

async에서 발생한 예외가 어떻게 전파되는지, 그리고 try-await를 언제 사용하는지 이해해 보세요. 브라우저에서 직접 실행하는 실습 코드로 Kotlin Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Kotlin Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Kotlin Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.

“async/await 예외 전파” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Kotlin Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Kotlin Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. SupervisorJob과 Job 비교: 실패 격리
  2. CoroutineExceptionHandler: 전역 미처리 예외 처리기
  3. async/await 예외 전파
  4. 복원력 있는 코루틴 아키텍처 설계
← Kotlin Academy(으)로 돌아가기