协程不使用配置的记录器

问题描述 投票:0回答:1

以某种方式启动协程时,我注意到,当它失败时,它不会使用配置的 Log4j 记录器来记录异常,而是将其记录到 stderr。尽管与现实世界的场景相去甚远,但下面的内容代表了展示该问题的最小可重现片段。

@RestController
class SoDemoController {
    @GetMapping("/demo")
    fun demo(): ResponseEntity<String> {
        CoroutineScope(Dispatchers.Default).launch {
            async {
                // Something useful is done here
                delay(1000)
                error("some error happens")
            }.await()
        }

        return ResponseEntity.ok("done")
    }
}

输出:

Exception in thread "DefaultDispatcher-worker-3" java.lang.IllegalStateException: some error happens
...

现在,出于某种原因使用

runBlocking
解决了问题。

@RestController
class SoDemoController {
    @GetMapping("/demo")
    fun demo(): ResponseEntity<String> {
        runBlocking {
            async {
                // ... rest of the code ...

输出:

2024-04-13T14:08:36.091+01:00 ERROR 5771 --- [demo] [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.IllegalStateException: some error happens] with root cause

虽然我理解

runBlocking
CoroutineScope.launch
之间的行为是不同的,因为一个阻塞线程,另一个阻塞线程,就目前而言,它是即发即忘,但我不太明白它如何影响通道日志已完成(stderr 与 log4j)。

这种差异背后的原因是什么?解决它的最佳方法是什么?关于是否使用

runBlocking
的争论有时令人困惑,我不确定在这种情况下是否有更好的方法。

spring kotlin log4j kotlin-coroutines
1个回答
0
投票

这两种情况有很大不同。

如果使用

runBlocking
demo
函数将等待协程完成。如果协程失败,则从
demo
函数抛出异常。这会导致 500 错误,Spring 知道该异常并根据其配置记录它。

如果使用

launch
,协程会在后台启动,
demo
成功返回,Spring甚至不知道后台有任务在运行。任务由协程框架管理,而不是由 Spring 管理。如果协程失败,Spring 甚至不知道这一点。错误由协程框架记录,当然,协程对 Spring 及其日志配置一无所知。协程机器根据打印到 stderr 的默认行为记录消息。

如果您想更改协程中错误的处理方式,您可以提供

CoroutineExceptionHandler
,如下所述:https://kotlinlang.org/docs/exception-handling.html#coroutineexceptionhandler

© www.soinside.com 2019 - 2024. All rights reserved.