kevinherron
12/14/2018, 12:28 PMfun main(args: Array<String>) {
val job = SupervisorJob()
val scope = CoroutineScope(job + Dispatchers.Default)
val deferred = GlobalScope.async(Dispatchers.Default, start = CoroutineStart.LAZY) {
delay(5000)
throw Exception("boom")
}
scope.launch {
try {
deferred.await()
} catch (e: Exception) {
println("error awaiting: $e")
}
}
runBlocking { job.cancelAndJoin() }
Thread.sleep(10000)
}
Evgeniy Zaharov
12/14/2018, 12:34 PMasync
in another scope (global) so it runs independent from your supervisor job (which exception you see like Exception in thread “DefaultDispatcher-worker-1”.. )
all other coroutines are in one scope, so then you cancel job
by cancelAndJoin
, you also cancel launch
(running in scope.launch)kevinherron
12/14/2018, 12:35 PMkevinherron
12/14/2018, 12:36 PMasync
Evgeniy Zaharov
12/14/2018, 12:36 PMkevinherron
12/14/2018, 12:36 PMasync
blocksEvgeniy Zaharov
12/14/2018, 12:37 PMkevinherron
12/14/2018, 12:39 PMawait()
. If I cancel the only caller, nothing is `await()`ing any more, so why the exception?Evgeniy Zaharov
12/14/2018, 12:40 PMkevinherron
12/14/2018, 12:42 PMkevinherron
12/14/2018, 12:43 PMEvgeniy Zaharov
12/14/2018, 12:51 PMkevinherron
12/14/2018, 12:55 PMkevinherron
12/14/2018, 12:55 PMEvgeniy Zaharov
12/14/2018, 1:54 PMis CancelledContinuation -> {
/*
* If continuation was cancelled, then all further resumes must be
* ignored, because cancellation is asynchronous and may race with resume.
* Racy exception are reported so no exceptions are lost
*
* :todo: we should somehow remember the attempt to invoke resume and fail on the second attempt.
*/
if (proposedUpdate is CompletedExceptionally) {
handleException(proposedUpdate.cause)
}
return
}
Evgeniy Zaharov
12/14/2018, 1:55 PMEvgeniy Zaharov
12/14/2018, 2:01 PMinternal fun handleExceptionViaHandler(context: CoroutineContext, exception: Throwable) {
// Invoke exception handler from the context if present
try {
context[CoroutineExceptionHandler]?.let {
it.handleException(context, exception)
return
}
} catch (t: Throwable) {
handleCoroutineExceptionImpl(context, handlerException(exception, t))
return
}
// If handler is not present in the context or exception was thrown, fallback to the global handler
handleCoroutineExceptionImpl(context, exception)
}
no handles is present, so it throws with handleCoroutineExceptionImpl
internal actual fun handleCoroutineExceptionImpl(context: CoroutineContext, exception: Throwable) {
// use additional extension handlers
for (handler in handlers) {
try {
handler.handleException(context, exception)
} catch (t: Throwable) {
// Use thread's handler if custom handler failed to handle exception
val currentThread = Thread.currentThread()
currentThread.uncaughtExceptionHandler.uncaughtException(currentThread, handlerException(exception, t))
}
}
// use thread's handler
val currentThread = Thread.currentThread()
currentThread.uncaughtExceptionHandler.uncaughtException(currentThread, exception)
}
kevinherron
12/16/2018, 3:36 PMEvgeniy Zaharov
12/17/2018, 7:52 AM