Manual context propagation in Quarkus native mode(Quarkus纯模式下的手动上下文传播)
问题描述
我正在尝试使上下文传播在Quarkus纯模式下工作。
以下代码在JVM模式下按预期工作,但在本机模式下返回MDC value: null
。
正如预期的那样,我的意思是:
对curl http://localhost:8080/thread-context
的响应是MDC value: from-thread-context
@Inject
ManagedExecutor managedExecutor;
@Inject
ThreadContext threadContext;
private final Supplier<String> mdcValueSupplier =
() -> "MDC value: " + MDC.get("foo") + "
";
@GET
@Path("thread-context")
public String get() throws ExecutionException, InterruptedException {
MDC.put("foo", "from-thread-context");
Supplier<String> ctxSupplier = threadContext.contextualSupplier(mdcValueSupplier);
return managedExecutor.supplyAsync(ctxSupplier).get();
}
我已经创建了一个github repo,其中包含演示应用的完整代码和重现该问题的逐步说明。
存在依赖项io.quarkus:quarkus-smallrye-context-propagation
。
Quarkus版本:1.9.2
问:是我的代码有问题,还是Quarkus有问题?
参考:Quarkus documentatin on context propagation
推荐答案
您的代码基本上很好[1],Quarkus在这方面也很好--但有两件事需要理解。
第一,您没有执行任何类型的手动上下文传播。您的代码是意外运行的,因为Quarkus使用JBoss LogManager作为记录器,并且它的MDC不是普通的ThreadLocal
,它是一个InheritableThreadLocal
。因此,它有时会传播上下文本身。但这并不是可以依赖的。例如,如果您执行实时重新加载(通过稍微修改代码并再次运行curl
),它也将停止在JVM模式下工作。
第二,上下文传播的要点是将线程本地状态从一个线程转移到另一个线程,但这不是自动发生的。您可以通过调用相应的API自己执行该操作(即手动上下文传播),也可以实现ThreadContextProvider
。
我简要介绍了MDC API(http://www.slf4j.org/api/org/slf4j/MDC.html),似乎可以使用getCopyOfContextMap
和setContextMap
实现基本的上下文传播。下面是我快速组装的一个实现--注意,我没有对代码进行太多测试:
import org.eclipse.microprofile.context.spi.ThreadContextProvider;
import org.eclipse.microprofile.context.spi.ThreadContextSnapshot;
import org.slf4j.MDC;
import java.util.Map;
public class MdcContextProvider implements ThreadContextProvider {
@Override
public ThreadContextSnapshot currentContext(Map<String, String> props) {
Map<String, String> propagate = MDC.getCopyOfContextMap();
return () -> {
Map<String, String> old = MDC.getCopyOfContextMap();
MDC.setContextMap(propagate);
return () -> {
MDC.setContextMap(old);
};
};
}
@Override
public ThreadContextSnapshot clearedContext(Map<String, String> props) {
return () -> {
Map<String, String> old = MDC.getCopyOfContextMap();
MDC.clear();
return () -> {
MDC.setContextMap(old);
};
};
}
@Override
public String getThreadContextType() {
return "SLF4J MDC";
}
}
如果您创建的META-INF/services/org.eclipse.microprofile.context.spi.ThreadContextProvider
文件包含此类的完全限定名称,则MDC传播应该适用于您,即使是在本机中也是如此。
MDC
所做的任何更改都不会传播回原始线程,因为SLF4J故意不提供对后备映射的访问,它只分发副本。这对你来说可能没问题,也可能不好。
[1]如果您将ManagedExecutor
提交给ManagedExecutor
,则Supplier
您的Supplier
不必将Supplier
提交给ManagedExecutor
,ManagedExecutor
会自动执行此操作。
这篇关于Quarkus纯模式下的手动上下文传播的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!