簡體   English   中英

將異常從異步傳播到 CoroutineExceptionHandler

[英]Propagate exception from async to CoroutineExceptionHandler

我有一個async協程,可能會引發異常。 如何將異常傳播到我的CoroutineExceptionHandler 使用try/catch await我能夠捕獲異常,但無論上下文如何,我似乎都無法將處理傳播到處理程序:

val handler = CoroutineExceptionHandler { _, e -> e.printStackTrace() }
val context = Executors.newSingleThreadExecutor().asCoroutineDispatcher() + handler
val scope = CoroutineScope(context)

val async = scope.async {
    throw Exception("Test exception")
}
runBlocking {
    try {
        async.await()
    } catch (e: Exception) {
        log.error("Exception thrown", e)
    }
    delay(1_000)
}

我嘗試從 catch 中重新拋出異常,或者用以下一些結構包裝它:

catch (e: Exception) {
    throw e
    // withContext(context) { throw e }
    // scope.launch { throw e }
    // supervisorScope { throw e }
}

可悲的是,他們都沒有將其傳播給處理程序。 我可以以某種方式將CoroutineExceptionHandlerasync協程一起使用嗎?

有幾種方法可以使它工作。 首先,正如異步文檔中所述,它會在失敗時取消父作業。 這就是為什么scope.launch { throw e }什么都不做,到那時 scope 被取消了,協程甚至沒有啟動。

然后,正如受監督協程文檔中所述,要在受監督的上下文中處理未捕獲的異常,您應該將處理程序安裝到孩子的上下文中。 因此,例如以下代碼會將異常傳遞給您的處理程序

runBlocking {
   supervisorScope {
      launch(handler){
         async.await()
      }
   }
}   

go 的另一種方法是將異常處理程序安裝到協程的根 scope 中,例如像這樣

runBlocking {
   GlobalScope.launch(handler) {
      async.await()
   }.join()
}

這里我使用GlobalScope進行演示,但它可以是任何活動的(未取消的)scope。

協程異常處理文檔中有許多示例,我建議您也檢查並運行它們。

不,你不能。

async返回一個 Deferred,就像一個未來。 異常處理程序不適用,因為如果有異常,它就是 Deferred 的返回值。

從文檔:

除此之外,async builder 總是捕獲所有異常並在生成的 Deferred object 中表示它們,因此它的 CoroutineExceptionHandler 也不起作用。

來源: https://kotlinlang.org/docs/exception-handling.html#coroutineexceptionhandler

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM