在这种情况下,我需要传播一些状态,如跟踪器/跨度或每个请求的请求上下文。 jdk环境是21.0.1-preview。
我尝试通过通用方式在线程和虚拟线程之间传播任何状态。
喜欢:
class xxxDecorator implements TaskDecorator {
...
public Runnable decorate(@Nonnull Runnable runnable) {
var bindingsSnapshot = new ScopedValueMap();
for (var key : keys) {
bindingsSnapshot.put(key);
}
return () -> {
ScopedValue.Carrier carrier = ScopedValue.where(TRACER_SCOPED_VALUE, bindingsSnapshot.get(TRACER_SCOPED_VALUE));
for (var key : keys) {
carrier = carrier.where(key, bindingsSnapshot.get(key));
}
carrier.run(runnable);
};
}
}
@Slf4j
class ServiceImpl {
public void xxx() {
try (var executor = new SimpleAsyncTaskExecutor("pg-")) {
executor.setVirtualThreads(true);
var decorator = new PropagatingTaskDecorator();
executor.setTaskDecorator(decorator);
executor.setThreadFactory(Thread.ofVirtual().name("v-").factory());
executor.submit(() -> {
log.info("{}", xxx); // here log4j2 need print trace info by %X{traceId}
// but how count MDC work for ScopedValue
// up to now, i overwrite the ThreadContextMap and
// try to split virtual/platform thread for different
// way.
});
}
}
}
有人可以帮我一个忙吗?
欢迎来到精彩的SO,感谢您提出有趣的问题!
首先,从
ScopeValue
用法的角度来看,我认为您的代码是非常正确的。我无法理解代码中的 bindingsSnapshot
变量和 ScopedValueMap
类,但是如果您声明 TRACER_SCOPED_VALUE
常量,例如
private static final ScopedValue<String> TRACER_SCOPED_VALUE = ScopedValue.newInstance();
,创建一个带有值
的
Carrier
ScopedValue.Carrier carrier = ScopedValue.where(TRACER_SCOPED_VALUE, "Long live SO!");
,那么在执行任务时,您将能够检索该值:
String value = TRACER_SCOPED_VALUE.get();
因此,我相信,它实现了将状态 (
TRACER_SCOPED_VALUE
) 从“线程”(执行 ServiceImpl.xxx
、执行器的 submit
和装饰器的 decorate
)传播到“虚拟线程”的目标”,由执行者发起。
对于 MDC,(
BasicMDCAdapter
,LogbackMDCAdapter
)它使用 ThreadLocal
,而不是当前可用的最新版本中的 ScopeValue
。 ThreadLocal
和ScopeValue
虽然针对类似的问题,但在技术上是不相关的。所以,回答
到目前为止,计数 MDC 如何为 ScopedValue 工作是“MDS 没有”。
您能否详细说明以下内容:
我覆盖 ThreadContextMap 并尝试以不同的方式分割虚拟/平台线程。
?