Quarkus Reactive调用Hibernate Reactive报vertx事件循环线程阻塞异常
报错信息
IllegalStateException: The current thread cannot be blocked: vert.x-eventloop-thread-1
问题场景
使用Quarkus Reactive API从Hibernate Reactive服务拉取数据时固定触发上述错误,错误定位在存在内部方法调用的业务方法中。
相关代码
Quarkus API层代码
@GET @Path("/getEquipCls") public Uni<List<Tuple>> getMethod() { return reactiveMethod(); }
Hibernate Reactive服务层响应式方法代码
@Override public Uni<List<Tuple>> reactiveMethod(params) { Long variable = methodForVariable.await().indefinitely(); return reactiveMethod(variable); }
已尝试操作
已尝试添加@Blocking、@NonBlocking注解修复问题,均未生效。
错误根因
Vert.x事件循环线程(即报错中的vert.x-eventloop-thread-1)严禁执行任何阻塞操作,代码中调用的.await().indefinitely()是典型的阻塞等待方法,直接触发了线程保护异常。
之前添加@Blocking注解不生效的核心原因是:该注解仅对CDI代理拦截到的外部调用公共方法生效,类内部自调用的方法、非公共方法不会触发拦截器逻辑,方法依旧运行在事件循环线程上,不会切换到阻塞工作线程池。
可行解决方案
- 方案1(推荐,符合响应式编程规范):彻底移除阻塞调用,使用响应式链式操作替代主动等待,全程不阻塞事件循环,示例写法:
@Override public Uni<List<Tuple>> reactiveMethod(params) { // 直接链式调用,不阻塞等待中间结果 return methodForVariable.flatMap(variable -> reactiveMethod(variable)); }
该写法完全适配Quarkus Reactive与Hibernate Reactive的编程模型,无额外线程切换开销,是官方推荐的标准写法。
- 方案2(适配必须使用阻塞逻辑的场景,不推荐):将包含
.await().indefinitely()阻塞逻辑的代码拆分到独立CDI Bean的公共方法中,在该公共方法上添加@Blocking注解,保证方法被外部调用时会被拦截器切换到阻塞工作线程池执行,避免占用事件循环线程。注意不要在类内部直接自调用带@Blocking注解的方法,否则注解不会生效。
注意:Hibernate Reactive为全响应式框架,非必要不要混用阻塞API与响应式API,否则极易出现线程阻塞、上下文丢失等难以排查的问题。
内容的提问来源于stack exchange,提问作者Nabil Ansari
相关产品推荐
相关产品推荐

