在我运行Mono的awaitSingle之后MDCContext变空(带有kotlin挂起协程的Spring webflux)

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

我想问一下为什么MDCContext在调用Mono的awaitSingle后变空了

这是代码片段

suspend fun getTemplates(request: GetPaginatedTemplateServiceRequest): PaginationTemplates {
        var context = MDCContext()
        val count = templateRepository.findByName(
            request.templateName
        ).awaitSingle()
        context = MDCContext()
}

您的信息模板存储库正在使用 ReactiveMongo。

第一次调用 MDCContext,我在该函数之前生成的上下文映射中有一些

x-request-id

但是在我用 Mono 调用awaitSingle之后,MDCContext 变空了(这是我不期望的)

我尝试的一个解决方案是用 withContext 函数包装awaitSingle

下面的例子

        var context = MDCContext()
        val count = withContext(Dispatchers.IO.plus(MDCContext())) {
            templateRepository.findTemplatesCount(
                request.templateName
            ).awaitSingle()
        }
        context = MDCContext()

然后 mdc 上下文的第二次调用仍然包含像第一次调用一样的项目(这是我所期望的)。

我实际上可以使用该解决方案,但是已经有很多代码像这样使用awaitSingle。有什么简单的解决方案吗?可能就像自动将上下文传递给单声道或其他东西?

谢谢,如果不够清楚请告诉我

spring-boot kotlin spring-webflux kotlin-coroutines
1个回答
0
投票

MDCContext
需要跨异步边界进行显式管理。不幸的是,
ReactiveMongo
本身并不处理此上下文的传播。

没有一种自动方法将上下文传递给每个

Mono
操作,除非反应式库明确支持此上下文传播。 一些反应式框架可能会自动传播上下文,而其他框架可能不会。

本质上,使用

withContext
的当前解决方案是维持跨awaitSingle()
调用上下文的最实用的方法。

继续使用已经实现的

withContext

 方法来确保上下文传播;并考虑将其封装到可重用的实用程序中,包装需要上下文的异步操作。

以下是封装上下文传播逻辑的草稿示例。

import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.slf4j.MDC import reactor.core.publisher.Mono suspend fun <T> withMdcContext(block: suspend () -> T): T { val contextMap = MDC.getCopyOfContextMap() ?: emptyMap() return withContext(Dispatchers.IO + MDCContext(contextMap)) { block() } } // Extension function for context preservation fun <T> Mono<T>.preserveContext(): Mono<T> = this.subscriberContext { context -> val mdcContext = context.get(MDCContext::class.java) context + (mdcContext ?: MDCContext()) }
调用 

preserveContext()

 显式确保在反应操作之前设置的任何上下文都保留在整个反应链中。
在上下文传播的默认行为在各种反应式库之间可能不一致的情况下,这是保护上下文完整性的主动步骤。

suspend fun getTemplates(request: GetPaginatedTemplateServiceRequest): PaginationTemplates { val count = withMdcContext { templateRepository.findByName(request.templateName) .preserveContext() // Ensure context preservation in Mono .awaitSingle() } // ... }
    
© www.soinside.com 2019 - 2024. All rights reserved.