我正在尝试将我的断路器代码从Hystrix迁移到Resilience4j。通信是在两个应用程序之间进行的,其中一个应用程序是包含java代码本身中所有弹性4j配置的工件,第二个应用程序是微服务直接使用它。
有一个RequestId在微服务中生成,并传播到工件上下文,在那里它被打印到日志中。使用Hystrix时,它工作得非常好,但是自从我转移到resilience之后,我的请求Id就变成了空。
下面是我对批量头部和上下文传播器的配置:
ThreadPoolBulkheadConfig bulkheadConfig = ThreadPoolBulkheadConfig.custom()
.maxThreadPoolSize(maxThreadPoolSize)
.coreThreadPoolSize(coreThreadPoolSize)
.queueCapacity(queueCapacity)
.contextPropagator(new DummyContextPropagator())
.build();
// Bulk Head Registry
ThreadPoolBulkheadRegistry bulkheadRegistry = ThreadPoolBulkheadRegistry.of(bulkheadConfig);
// Create Bulk Head
ThreadPoolBulkhead bulkhead = bulkheadRegistry.bulkhead(name, bulkheadConfig);虚拟上下文传播器:
public class DummyContextPropagator implements ContextPropagator {
private static final Logger log = LoggerFactory.getLogger( DummyContextPropagator.class);
@Override
public Supplier<Optional<Object>> retrieve() {
return () -> (Optional<Object>) get();
}
@Override
public Consumer<Optional<Object>> copy() {
return (t) -> t.ifPresent(e -> {
clear();
put(e);
});
}
@Override
public Consumer<Optional<Object>> clear() {
return (t) -> DummyContextHolder.clear();
}
public static class DummyContextHolder {
private static final ThreadLocal threadLocal = new ThreadLocal();
private DummyContextHolder() {
}
public static void put(Object context) {
if (threadLocal.get() != null) {
clear();
}
threadLocal.set(context);
}
public static void clear() {
if (threadLocal.get() != null) {
threadLocal.set(null);
threadLocal.remove();
}
}
public static Optional<Object> get() {
return Optional.ofNullable(threadLocal.get());
}
}
}然而,似乎什么都不起作用,所以我可以获得RequestId。
我做的每件事都是正确的,还是有其他方法可以做到这一点?
发布于 2021-05-26 11:53:51
我认为当你在子线程中时,你应该从父线程中获取参数,在hystrix中使用command-model来修饰callabletask
在resilience4j中,我认为你可以像这样修复它:
@Resource
DispatcherServlet dispatcherServlet;
@PostConstruct
public void changeThreadLocalModel() {
dispatcherServlet.setThreadContextInheritable(true);
}发布于 2021-05-26 14:35:04
我发现当您使用"dispatcherServlet.setThreadContextInheritable(true);“时,我的上一个答案可能会导致一些问题
它可能会污染您的自定义线程池的threadlocalmap;
这是我的最终解决方案,它只适用于resilience4j;
@Resource
Resilience4jBulkheadProvider resilience4jBulkheadProvider;
@PostConstruct
public void concurrentThreadContextStrategy() {
ThreadPoolBulkheadConfig threadPoolBulkheadConfig = ThreadPoolBulkheadConfig.custom().contextPropagator(new CustomInheritContextPropagator()).build();
resilience4jBulkheadProvider.configureDefault(id -> new Resilience4jBulkheadConfigurationBuilder()
.bulkheadConfig(BulkheadConfig.ofDefaults()).threadPoolBulkheadConfig(threadPoolBulkheadConfig)
.build());
}
private static class CustomInheritContextPropagator implements ContextPropagator<RequestAttributes> {
@Override
public Supplier<Optional<RequestAttributes>> retrieve() {
// give requestcontext to reference from threadlocal;
// this method call by web-container thread, such as tomcat, jetty,or undertow, depends on what you used;
return () -> Optional.ofNullable(RequestContextHolder.getRequestAttributes());
}
@Override
public Consumer<Optional<RequestAttributes>> copy() {
// load requestcontex into real-call thread
// this method call by resilience4j bulkhead thread;
return requestAttributes -> requestAttributes.ifPresent(context -> {
RequestContextHolder.resetRequestAttributes();
RequestContextHolder.setRequestAttributes(context);
});
}
@Override
public Consumer<Optional<RequestAttributes>> clear() {
// clean requestcontext finally ;
// this method call by resilience4j bulkhead thread;
return requestAttributes -> RequestContextHolder.resetRequestAttributes();
}
}https://stackoverflow.com/questions/67283655
复制相似问题