Почему CoroutineExceptionHandler не перехватил / обработал мое исключение? - PullRequest
0 голосов
/ 05 мая 2018

В этом коде почему handler печатает трассировку стека только для JobCancellationException, а не SocketException? Функция foo внутри launch определенно выбрасывает SocketException, что с ней происходит?

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)
}

1 Ответ

0 голосов
/ 02 декабря 2018

Я не могу сказать вам, почему CoroutineExceptionHandler не уловил исключение, выданное launch. Но я могу сказать вам 2 вещи -

  1. Я проверил найденное вами поведение - вы правы, исключение не обнаружено.
  2. Экспериментируя, я научился ловить исключение в CoroutineExceptionHandler.

Вот код, который показывает, как его поймать:

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()

Вывод на консоль:

[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

Ключевым выводом является то, что если вы вызовете launch для пользовательского CoroutineScope, любой CoroutineExceptionHandler, предоставленный непосредственно конструктору CoroutineScope или launch, будет выполнен, когда в * 1023 будет сгенерировано исключение * ed сопрограмма.

Надеюсь, это поможет !!

UPDATE

Я выяснил, почему исключение не поймано. Смотрите мой ответ здесь .

...