Reputation: 1491
In this code why handler
only prints the stack-trace for JobCancellationException
and not SocketException
? The foo
function inside launch
definitely throws SocketException
, so what happens to it?
suspend fun foo() {
val job = coroutineContext[Job]!!
val socket = Socket()
job.invokeOnCompletion(onCancelling = true) {
if (!socket.isClosed) {
socket.close()
}
}
// non-routable address -> timeout
// will throw SocketException after socket.close() is called above
socket.connect(InetSocketAddress("10.0.0.0", 1234), 2000)
}
fun test() = runBlocking {
val handler = CoroutineExceptionHandler { _, throwable ->
throwable.printStackTrace()
}
val job = launch(DefaultDispatcher + handler) {
foo()
}
delay(100)
job.cancelAndJoin()
delay(100)
}
Upvotes: 3
Views: 5313
Reputation: 11450
I can't tell you why CoroutineExceptionHandler
didn't catch the exception thrown in launch
. But I can tell you 2 things -
CoroutineExceptionHandler
.Here's the code that shows how to catch it:
fun f() = runBlocking {
val eh = CoroutineExceptionHandler { _, e -> trace("exception handler: $e") }
val cs1 = CoroutineScope(Dispatchers.Default)
val j1 = cs1.launch(eh + CoroutineName("first")) {
trace("launched")
delay(1000)
throw RuntimeException("error!")
}
trace("joining j1")
j1.join()
val cs2 = CoroutineScope(Dispatchers.Default + eh)
val j2 = cs2.launch(CoroutineName("second")) {
trace("launched")
delay(1000)
throw RuntimeException("error!")
}
trace("joining j2")
j2.join()
trace("after join")
}
f()
Console output:
[main @coroutine#1]: joining j1
[DefaultDispatcher-worker-1 @first#2]: launched
[DefaultDispatcher-worker-1 @first#2]: exception handler: java.lang.RuntimeException: error!
[main @coroutine#1]: joining j2
[DefaultDispatcher-worker-1 @second#3]: launched
[DefaultDispatcher-worker-3 @second#3]: exception handler: java.lang.RuntimeException: error!
[main @coroutine#1]: after join
The key takeaway is that if you call launch
on a custom CoroutineScope
, any CoroutineExceptionHandler
provided directly to the CoroutineScope
constructor or to launch
will be executed when an exception is thrown within the launch
ed coroutine.
Hope that helps!!
UPDATE
I found out why the exception isn't caught. See my answer here.
Upvotes: 2