async を使ってるのに例外をawaitで捕獲できずアプリが落ちる…? というのを体験した。
理由の説明はこの記事が詳しかった。 https://star-zero.medium.com/coroutines-asyncとexception-9c0f079edb0e
- 親のキャンセルは子に伝えたい
- 子の例外はawait()で受け取りたい
…という用途では supervisorScope{} を使うのが良さそう。
スクラッチで試してみて概ね期待どおりだった。
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.supervisorScope
import java.lang.Thread.sleep
val scope = CoroutineScope(Job())
val job = scope.launch {
try {
supervisorScope {
val tasks = listOf(
async {
try {
delay(333L)
error("Test")
} catch (ex: Throwable) {
println("catch ex in async. ${ex.message}")
throw ex
}
}
)
try {
tasks.awaitAll()
} catch (ex: Throwable) {
println("catch ex in awaitAll. ${ex.message}")
throw ex
}
println("awaitAll complete.")
}
println("supervisorScope complete.")
} catch (ex: Throwable) {
println("catch ex in launch. ${ex.message}")
ex.printStackTrace()
}
println("launch complete.")
}
sleep(100L)
runBlocking {
// async内部からの例外発生を試したい場合
job.join()
// catch ex in async. Test
// catch ex in awaitAll. Test
// catch ex in launch. Test
// launch complete.
// または、上流からのキャンセル到達を試したい場合
// job.cancelAndJoin()
// catch ex in awaitAll. StandaloneCoroutine was cancelled
// catch ex in async. StandaloneCoroutine was cancelled
// catch ex in launch. StandaloneCoroutine was cancelled
// launch complete.
}
println("end.")
You must log in or register to comment.