异步线程里日志 traceId 丢失,怎么把上下文透传过去

MDC 的底层是 ThreadLocal,线程池复用线程,上下文不会自己跟过去。

提交任务前先把 MDC 的内容取出来,在子线程里 set 回去。

用 TaskDecorator 装饰线程池,包一层就能全局生效,不用改业务代码。

记得在 finally 里 clear,线程池复用时不清理会把脏数据带给下个任务。

// 1) 最简单:手动透传
Map<String, String> ctx = MDC.getCopyOfContextMap();
executor.submit(() -> {
    if (ctx != null) MDC.setContextMap(ctx);
    try { doWork(); } finally { MDC.clear(); }   // 必须清,线程会复用
});

// 2) 推荐:TaskDecorator 装饰线程池,全局生效
@Bean
public Executor taskExecutor() {
    ThreadPoolTaskExecutor ex = new ThreadPoolTaskExecutor();
    ex.setCorePoolSize(8);
    ex.setTaskDecorator(runnable -> {
        Map<String, String> c = MDC.getCopyOfContextMap();
        return () -> {
            if (c != null) MDC.setContextMap(c);
            try { runnable.run(); } finally { MDC.clear(); }
        };
    });
    ex.initialize();
    return ex;
}
// 注意:@Async 要指定这个执行器(@Async("taskExecutor"))。
//       CompletableFuture.supplyAsync 默认走 ForkJoinPool,不会用这个装饰器。
THE END
喜欢就支持一下吧
点赞14 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容