https://kotlinlang.org logo
#coroutines
Title
# coroutines
p

Paulius Ruminas

08/27/2019, 6:58 PM
Hello, is there a more idiomatic way to catch all errors but
CancellationException
? Cancelling the job is a normal operation that is not considered as an error. Code snippet:
Copy code
job = scope.launch {
                    try {
                         // proccess the action
                    } catch (e: CancellationException) {
                        throw e
                    } catch (e: Throwable) {
                        // log the error
                    }
 }
r

reline

08/27/2019, 7:02 PM
how’s this?
Copy code
job = scope.launch {
                    try {
                         // proccess the action
                    } catch (e: Throwable) {
                        coroutineContext.ensureActive()
                        // log the error
                    }
 }
m

Marc Knaup

08/27/2019, 7:06 PM
Wouldn’t the stack trace of the initial exception be lost?
What about a one-line check in the catch block? It’s still repetitive but at least you won’t need two catch blocks.
Copy code
if (e is CancellationException) throw e
Or make it an extension function:
Copy code
e.rethrowCancellation()
p

Paulius Ruminas

08/27/2019, 7:08 PM
The thing is that when we onboard new developers that are not familiar with coroutines they forget/do not know yet to bubble the
CancellationException
when catching all errors. I see a lot of
Job was cancelled
in our kibana logs which are just job cancellations not real errors so I was wondering is there a different approach.
r

reline

08/27/2019, 7:09 PM
@Marc Knaup hmm, in the case that a CancellationException was not thrown and by the time you call
ensureActive()
the coroutine is no longer active then yes, you’re correct. Is that possible?
m

Marc Knaup

08/27/2019, 7:09 PM
Would be nice if
CancellationException
would just be a
Throwable
and catch-all is just
e: Exception
. Catching
Throwable
is still evil, isn’t it? 😄
p

Paulius Ruminas

08/27/2019, 7:10 PM
It is but it's a worker function that needs to keep processing other actions event if one fails.
m

Marc Knaup

08/27/2019, 7:12 PM
Sure it does. But non-exceptions are usually
Error
and that means something is REALLY wrong (like
OutOfMemoryError
). I’d rather restart the server then and fix asap than trying to keep a potentially unstable JVM alive.
You could also be very hacky and make your logging function rethrow
CancellationException
instead of logging it 😂
.logIfNotCancel
🙂
Or actually if it’s just about logging then make it a reusable functionality! No need to always wrap all
launch
code into
try … catch (Throwable)
scope.launchWithExceptionLogging { … }
I think it can be done even without a custom extension by installing an exception handler in your coroutine context(s).
g

gildor

08/28/2019, 4:14 AM
I prefer explicit exception management with try/catch instead of exceptionhandler
👆 1
m

Marc Knaup

08/28/2019, 2:41 PM
Even if it’s just for the purpose of logging all exceptions except one kind? Possibly across hundreds of call-sites? 🤔
g

gildor

08/28/2019, 3:04 PM
Depends on use case, if it's just simple launch + try/catch I would just write extension function. Also, to use exception handler you have to add to all contexts, also it doesn't work for non-supervisor job. So I don't see how it would be better than explicit logging, which also more flexible (you want just log and rethrow, or you want log and return default value or just ignore and cancel)
2 Views