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 AMisActivelouiscad
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?