quarkus本机模式下的手动上下文传播

nx7onnlm  于 2021-07-08  发布在  Java
关注(0)|答案(1)|浏览(713)

我正在尝试让上下文传播在quarkus本机模式下工作。
下面的代码在jvm模式下正常工作,但返回 MDC value: null 在本机模式下。
我所说的“如预期”是指:
对…的React curl http://localhost:8080/thread-contextMDC value: from-thread-context ```
@Inject
ManagedExecutor managedExecutor;

@Inject
ThreadContext threadContext;

private final Supplier mdcValueSupplier =
() -> "MDC value: " + MDC.get("foo") + "\n";

@GET
@Path("thread-context")
public String get() throws ExecutionException, InterruptedException {
MDC.put("foo", "from-thread-context");
Supplier 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
3htmauhk

3htmauhk1#

你的代码基本上是好的[1],quarkus在这方面也是好的——但是有两件事需要理解。
第一,你没有做任何形式的“手动上下文传播”。您的代码是偶然工作的,因为quarkus使用jboss logmanager作为记录器,并且它的mdc不是普通的 ThreadLocal ,这是一个 InheritableThreadLocal . 所以它有时会传播上下文本身。但这没什么可依赖的。例如,如果您执行实时重新加载(通过稍微修改代码并运行 curl 同样地,它也将停止在jvm模式下工作。
第二,上下文传播的关键是将线程的本地状态从一个线程转移到另一个线程,但这并不是自动发生的。您可以自己通过调用相应的api来实现(这将是“手动上下文传播”),也可以实现 ThreadContextProvider .
我简单地看了一下mdcapi(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故意不提供对备份Map的访问,它只分发副本。这对你来说也许是好的,或者不是。
[1] 你不必“语境化”你的想法 SupplierThreadContext.contextualSupplier 如果你把它交给 ManagedExecutor --那个 ManagedExecutor 自动完成。

相关问题