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

Quarkus EventBus requestAndForget 日志报超时错误问题咨询

问题现象

Quarkus 2.9.2.Final版本中使用EventBus组件,调用requestAndForget方法对接返回值为void、标注@ConsumeEvent的消费方法时,业务逻辑可正常执行,但日志会抛出如下超时异常:

OK
2022-06-07 09:44:04,064 ERROR [io.qua.mut.run.MutinyInfrastructure] (vert.x-eventloop-thread-1) Mutiny had to drop the following exception: (TIMEOUT,-1) Timed out after waiting 30000(ms) for a reply. address: __vertx.reply.3, repliedAddress: receivedSomeEvent

对应消费端代码:

@ApplicationScoped
public class ConsumerManiac{
  @ConsumeEvent(value = "receivedSomeEvent")
  public void consume(SomeEvent someEvent ) {
    System.out.println("OK");
  }
}

对应生产端REST接口代码:

public class SomeResource {
  private final EventBus eventBus;

  @Inject
  public SomeResource (EventBus eventBus) {
    this.eventBus = eventBus;
  }

  @POST
  public Response send(@Valid SomeEvent someEvent) {
    eventBus.requestAndForget("receivedSomeEvent", someEvent);
    return Response.accepted().build();
  }
}

如果把消费方法修改为返回任意值(比如返回String类型"ok"),日志中就不会出现上述异常:

@ApplicationScoped
public class ConsumerManiac{
  @ConsumeEvent(value = "receivedSomeEvent")
  public String consume(SomeEvent someEvent ) {
    System.out.println("OK");
    return "ok";
  }
}

完整异常栈如下:

2022-06-07 09:44:04,064 ERROR [io.qua.mut.run.MutinyInfrastructure] (vert.x-eventloop-thread-1) Mutiny had to drop the following exception: (TIMEOUT,-1) Timed out after waiting 30000(ms) for a reply. address: __vertx.reply.3, repliedAddress: receivedSomeEvent
at io.vertx.core.eventbus.impl.ReplyHandler.handle(ReplyHandler.java:76)
at io.vertx.core.eventbus.impl.ReplyHandler.handle(ReplyHandler.java:24)
at io.vertx.core.impl.VertxImpl$InternalTimerHandler.handle(VertxImpl.java:893)
at io.vertx.core.impl.VertxImpl$InternalTimerHandler.handle(VertxImpl.java:860)
at io.vertx.core.impl.EventLoopContext.emit(EventLoopContext.java:50)
at io.vertx.core.impl.DuplicatedContext.emit(DuplicatedContext.java:168)
at io.vertx.core.impl.AbstractContext.emit(AbstractContext.java:53)
at io.vertx.core.impl.VertxImpl$InternalTimerHandler.run(VertxImpl.java:883)
at io.netty.util.concurrent.PromiseTask.runTask(PromiseTask.java:98)
at io.netty.util.concurrent.ScheduledFutureTask.run(ScheduledFutureTask.java:170)
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:469)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:503)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:833)

原因说明

requestAndForget的语义是「发送请求、等待消费端回复,但业务代码不处理回复内容」,不是真正的发后即忘。调用该方法时,Vert.x EventBus会自动注册一个默认30s超时的回复监听器:

  • 如果消费方法有返回值,Quarkus会自动将返回值作为应答发回生产端,监听器收到应答后自动注销,不会触发超时
  • 如果消费方法返回值为void,Quarkus默认不会发送应答,监听器等满30s就会抛出超时异常,和业务逻辑是否执行成功无关
解决方法

两种方案都可以保留消费方法的void返回值,彻底消除日志报错:

  • 方案一(推荐):生产端改用send方法实现真正的发后即忘,语义完全匹配不需要等待回复的场景,修改后生产端发送代码为:
    eventBus.send("receivedSomeEvent", someEvent);
    
  • 方案二:如果一定要用requestAndForget,在消费端的@ConsumeEvent注解上显式配置关闭应答,配置方式为:
    @ConsumeEvent(value = "receivedSomeEvent", acknowledgement = ConsumeEvent.Acknowledgement.NONE)
    public void consume(SomeEvent someEvent ) {
      System.out.println("OK");
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 04:12:30