You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Vert.x EventBus时如何实现线程上下文传播?

在Quarkus EventBus中实现上下文传播的正确方式

问题分析

你遇到的核心问题是:Vertx ContextLocals和SLF4J MDC上下文在EventBus消息传递过程中没有自动传播。这是因为EventBus消费端默认在独立的线程(Vertx事件循环或EventBus线程池)执行,不会自动继承发送端的上下文;而你配置的ThreadContextProvider需要结合特定的执行上下文才能生效。


解决方案

1. SLF4J MDC自动传播(基于SmallRye Context Propagation)

你的ThreadContextProvider实现本身有效,只需调整消费端的执行模式,确保上下文能传播到EventBus消费线程:

  • 将消费方法改为返回Uni<String>,并添加@Blocking注解,让它在配置了上下文传播的ManagedExecutor中执行
  • 保留@CurrentThreadContext(propagated = {"SLF4J_MDC"})注解

修改后的消费端代码:

@Inject
Logger log;

@ConsumeEvent(value = "greeting")
@Blocking
@CurrentThreadContext(propagated = {"SLF4J_MDC"})
public Uni<String> greeting(String name) {
    log.info("MDC2 >>> {}", MDC.get("key")); // 现在可以获取到MDC值
    return Uni.createFrom().item("Hello " + name.toUpperCase());
}

发送端代码简化:
不需要额外的emitOn或runSubscriptionOn,EventBus的request会自动在Vertx上下文处理,上下文传播框架会捕获当前的MDC值:

@Inject
EventBus bus;

@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("{name}")
public Uni<String> hello(String name) {
    MDC.put("key", "someValue");
    ContextLocals.put("key", "Local Context");

    return bus.<String>request("greeting", name)
            .onItem().transform(Message::body);
}

2. Vertx ContextLocals 传播

ContextLocals是绑定到当前Vertx Context的本地变量,EventBus消费端默认不会在发送端的Context中执行,有两种处理方式:

方式一:手动通过消息头传递(通用方案,支持集群)

发送消息时将ContextLocals的值放入消息头:

return bus.<String>request("greeting", name, 
        new DeliveryOptions().addHeader("context-local-key", ContextLocals.get("key")))
        .onItem().transform(Message::body);

消费端从消息头中获取:

@ConsumeEvent(value = "greeting")
@Blocking
@CurrentThreadContext(propagated = {"SLF4J_MDC"})
public Uni<String> greeting(Message<String> message) {
    String name = message.body();
    String localValue = message.headers().get("context-local-key");
    log.info("from Context Local {}", localValue); // 可获取到值
    log.info("MDC2 >>> {}", MDC.get("key"));

    return Uni.createFrom().item("Hello " + name.toUpperCase());
}

方式二:强制消费端在发送端Context执行(仅本地EventBus有效)

如果你的EventBus是本地非集群模式,可以在发送时将消费逻辑绑定到当前Context:

return Uni.createFrom().emitter(emitter -> {
    Context currentContext = Vertx.currentContext();
    bus.request("greeting", name, ar -> {
        if (ar.succeeded()) {
            currentContext.runOnContext(v -> {
                emitter.complete(ar.result().body());
            });
        } else {
            emitter.fail(ar.cause());
        }
    });
});

这种方式下,消费端的ContextLocals.get("key")可以直接获取到值,但无法跨节点传播。


功能支持说明

Quarkus EventBus完全支持与上下文传播结合使用,但需注意:

  • 基于SmallRye Context Propagation的MDC等上下文,需要确保消费端在支持上下文传播的线程池(如@Blocking指定的ManagedExecutor)中执行
  • Vertx ContextLocals属于本地上下文,集群场景下无法自动传播,必须手动通过消息头传递

内容的提问来源于stack exchange,提问作者Cosmin Badea

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 17:06:56