ivan.savytskyi
11/14/2018, 8:17 PMkotlinx.coroutines.AwaitKt#awaitAll
. From KDocs:
Awaits for completion of given deferred values without blocking a thread and resumes normally with the list of values when all deferred computations are complete or resumes with the first thrown exception if any of computations complete exceptionally including cancellation.If I understand that right
resumes with the first thrown exception
. But having this example:
val exceptionHandler = CoroutineExceptionHandler { _, exception ->
println("exception handler $exception")
}
val scope = CoroutineScope(Dispatchers.Default + exceptionHandler)
scope.launch {
val firstCoroutine = async {
delay(300)
println("crashing first coroutine")
throw IllegalArgumentException()
}
val secondCoroutine = async {
try {
delay(700)
println("second coroutine still alive")
} catch (e: Exception) {
println("second coroutine try/catch $e")
}
"Done"
}
try {
awaitAll(firstCoroutine, secondCoroutine)
} catch (e: Exception) {
println("awaitAll try/catch $e")
}
}
I was expecting to see awaitAll try/catch java.lang.IllegalArgumentException
but instead I see awaitAll try/catch kotlinx.coroutines.JobCancellationException: Job is cancelling; job=StandaloneCoroutine{Cancelling}@27e6316a
.
Could someone pls explain this behaviour?bdawg.io
11/14/2018, 8:28 PMbdawg.io
11/14/2018, 8:29 PMasync
completes exceptionally, which cancels the second async
instead of waiting for it to completebdawg.io
11/14/2018, 8:32 PMtateisu
11/14/2018, 8:33 PMscope.launch {
+ println("launch scope = $this")
it shows StandaloneCoroutine same as catched cancelled job. maybe throwed exception in async is redirected to parent job. you can change receiver of async{} to GlobalScope.async{} to prevent cancel redirection.tateisu
11/14/2018, 8:37 PMoverride val cancelsParent: Boolean get() = true
ivan.savytskyi
11/14/2018, 8:38 PMJobCancellationException
that obviously comes from the second coroutine delay
? I was expecting it will report exception from first coroutine which is IllegalArgumentException
and that fails firsttateisu
11/14/2018, 8:40 PMivan.savytskyi
11/14/2018, 8:42 PMtateisu
11/14/2018, 8:42 PMivan.savytskyi
11/14/2018, 8:42 PMivan.savytskyi
11/14/2018, 8:43 PMval exceptionHandler = CoroutineExceptionHandler { _, exception ->
println("exception handler $exception")
}
val scope = CoroutineScope(Dispatchers.Default + exceptionHandler)
scope.launch {
val firstCoroutine = async {
delay(300)
println("crashing first coroutine")
throw IllegalArgumentException()
}
val secondCoroutine = async {
try {
delay(700)
println("second coroutine still alive")
} catch (e: Exception) {
println("second coroutine try/catch $e")
}
"Done"
}
try {
firstCoroutine.await()
} catch (e: Exception) {
println("awaitAll try/catch $e")
}
// try {
// awaitAll(firstCoroutine, secondCoroutine)
// } catch (e: Exception) {
// println("awaitAll try/catch $e")
// }
}
ivan.savytskyi
11/14/2018, 8:44 PMivan.savytskyi
11/14/2018, 8:44 PMivan.savytskyi
11/14/2018, 8:44 PMtateisu
11/14/2018, 8:47 PMtateisu
11/14/2018, 8:48 PMawaitAll()
, but I know async{}
redirects cancelled state to the parent job.tateisu
11/14/2018, 8:54 PM${e.cause}
to get IllegalArgumentExceptiontateisu
11/14/2018, 8:59 PM* This suspending function is cancellable.
* If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting,
* this function immediately resumes with [CancellationException].
bdawg.io
11/14/2018, 9:32 PMbdawg.io
11/14/2018, 9:33 PMJob
says Normal cancellation of a job is distinguished from its failure by the type of its cancellation exception cause. If the cause of cancellation is CancellationException, then the job is considered to be cancelled normally. This usually happens when cancel is invoked without additional parameters. If the cause of cancellation is a different exception, then the job is considered to have failed. This usually happens when the code of the job encounters some problem and throws an exception.