louiscad
07/16/2018, 7:34 AMjob.cancel(IllegalStateException(...))
from a callback, catch exceptions from the parent coroutine, but still get my app crashing. I replicated the issue in some tests, and the catch block is hit, but it seems the Exception is thrown no matter if it was caught in the parent coroutine. Is this really intended?elizarov
07/16/2018, 8:04 AMlouiscad
07/16/2018, 8:05 AMlouiscad
07/16/2018, 8:09 AM@Test
fun reproduceCancellationBug() = runBlocking {
try {
willCancel()
} catch (e: Exception) {
println("We caught something.. ;-)")
}
}
private suspend fun willCancel() {
val job = coroutineContext[Job]!!
job.cancel(IllegalStateException("Illegal stuff, going to court."))
}
gildor
07/16/2018, 8:13 AMlouiscad
07/16/2018, 8:14 AMelizarov
07/16/2018, 8:22 AMelizarov
07/16/2018, 8:23 AMyield
after willCancel
, then it is thrown and caught properlylouiscad
07/16/2018, 8:24 AMwillCancel
is not cancellable itself? BTW, I edited the snippet on try.kotl.in to add yield()
after willCancel()
and the exception is still thrownelizarov
07/16/2018, 8:25 AMyield
, delay
, receive
, or suspendCancellableCoroutine
at the lowest level)elizarov
07/16/2018, 8:25 AMisActive
louiscad
07/16/2018, 8:27 AMyield()
after willCancel()
helps having the catch
block executed, but the exception is still not really caught, see the snippet on the link I sharedelizarov
07/16/2018, 8:28 AMrunBlocking
job with exception, so it is now doomed to fail with this exception. Catching it does not help.louiscad
07/16/2018, 8:29 AMwillCancel
function cancel instead?elizarov
07/16/2018, 8:30 AMelizarov
07/16/2018, 8:30 AMelizarov
07/16/2018, 8:31 AMjob.cancel(...)
to cancel somebody else’s job, not your own job.louiscad
07/16/2018, 8:31 AMwillCancel
functionelizarov
07/16/2018, 8:31 AMsuspendCancellableCoroutine { cont -> ... }
and then while it is suspended you can cont.cancel()
elizarov
07/16/2018, 8:32 AMlouiscad
07/16/2018, 8:35 AMsuspend fun
that was there for the sole purpose of retrieving a Job
to cancel. Your solution won't be able to cancel the coroutine after it has returnedelizarov
07/16/2018, 8:36 AMelizarov
07/16/2018, 8:37 AMlouiscad
07/16/2018, 8:41 AMelizarov
07/16/2018, 8:43 AMfoo
, the coroutine, that it is part of, could be anywhere up the stack. I’d prefer and explicitly scoped block that clearly demarcates the beginning and the end of the corresponding scope.elizarov
07/16/2018, 8:44 AMwithTimeout
, for example. We don’t attach timeout to the current coroutine. Instead, we put all the code that need to have timeout in a separate scope.louiscad
07/16/2018, 8:46 AMlouiscad
07/16/2018, 8:46 AMlouiscad
07/16/2018, 9:27 AMCancellationException
(or leaving to default one) crashes the program though? I thought only non CancellationException
did so.louiscad
07/16/2018, 9:28 AMelizarov
07/16/2018, 9:34 AMrunBlocking
. It has to throw CancellationException
, but the fun main
would still print it on the console. If a coroutine terminated with CancellationException
it is considered “normal”louiscad
07/16/2018, 1:22 PMwithTimeout
, but it's forcing me to do code duplication as it needs to be used conditionally, which is not possible with this approach out of the box (while I could just swap listeners if I could cancel the coroutine from the callbacks)elizarov
07/16/2018, 2:16 PMlouiscad
07/16/2018, 2:50 PMwithXx
way still, with suspendCancellableCoroutine
, which I like since it is a bit more readable, but I don't know if I should use resume
and resumeWithException
or tryResume
and tryResumeWithException
or completeResume
and cancel
.
Also, when I run tests (Android instrumented tests), the coroutine launched with runBlocking
never resumes when cont.resume(...)
is invoked, but it works fine in non tests, where it's run with launch
from the UI thread instead. Any clue on what may cause this?