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

Quarkus响应式应用RestAssured测试触发IO线程阻塞问题

Quarkus响应式应用RestAssured单元测试报IO线程阻塞异常解决

问题现象

开发基于Quarkus的响应式应用,使用RestAssured编写单元测试执行时抛出如下异常:

[org.jbo.res.rea.ser.cor.RuntimeExceptionMapper] (vert.x-eventloop-thread-1) A blocking operation occurred on the IO thread. This likely means you need to annotate my.package.MyController#update(class my.package.MyRequestDto) with @io.smallrye.common.annotation.Blocking. Alternatively you can annotate the class my.package.MyController to make every method on the class blocking, or annotate your sub class of the javax.ws.rs.core.Application class to make the whole application blocking

直接启动应用通过Postman手动调用接口不会触发该异常,确认问题由测试环节配置缺失导致。

关联代码

测试类代码

@QuarkusTest
public class MyTest {
  @Test
  @TestReactiveTransaction
  public void test_A() {
              Response response = given()
                      .when()
                      .accept(MediaTypes.JSON_TYPE)
                      .contentType(MediaTypes.JSON_TYPE)
                      .body("{myRequestJsonHere}")
                      .patch("/path/to/api")
                      .then()
                      .extract().response();
      // asserts

  }
}

Controller层代码

@Path("/path/to/api")
@ApplicationScoped
public class MyController{
  @Inject MyService service;

  @PATCH
  public Uni<MyResultType> update(@NotNull @RequestBody @Valid MyRequestDto request) {
     return service.update(request);
  }
}

Service层代码

@ApplicationScoped
public class MyService {
  @Inject MyRepository repository;

  @Transactional
  public Uni<MyResultType> update(MyRequestDto request) {
    return repository.findAll().firstResult()
       .onItem().transform(l -> /* mapping here */)
       .flatMap(repository::persistAndFlush);
  }
}

Repository层代码

public interface MyRepository extends PanacheRepository<MyResultType> {
}

已尝试方案

  • 将测试逻辑整体包裹在UniAsserter.execute(() -> { });中执行,仍出现相同异常

根因分析

异常核心原因是测试链路被强制运行在Vert.x事件循环(IO)线程上,但链路中存在阻塞操作。
生产环境手动调用正常、测试调用报错的差异点在于:@TestReactiveTransaction注解会默认让测试执行及关联的请求处理全程运行在IO线程,禁用Quarkus默认的阻塞操作自动分配到工作线程的逻辑。当前代码存在两个明确的阻塞点:

  1. 原生RestAssured的given()...patch()是同步阻塞调用,会阻塞当前线程等待响应返回
  2. 代码中继承的PanacheRepository是阻塞版Hibernate ORM的接口,所有数据库操作都是阻塞执行的;Service层使用的@Transactional也是阻塞版事务注解,不适用于响应式链路

修复方案

根据你对应用响应式特性的要求,二选一即可:

方案1:保留全链路响应式(推荐)

按响应式规范修正全链路代码,避免阻塞操作出现在IO线程:

  • 修正Repository层:将继承的阻塞版PanacheRepository替换为响应式版io.quarkus.hibernate.reactive.panache.PanacheRepositoryReactive
  • 修正Service层:将阻塞版@Transactional替换为响应式事务注解@io.smallrye.hibernate.reactive.panache.common.ReactiveTransactional
  • 修正测试代码:
    • 要么移除测试方法上的@TestReactiveTransaction,替换为阻塞版测试事务注解@TestTransaction,让测试运行在工作线程,兼容现有同步RestAssured写法
    • 要么保留@TestReactiveTransaction,替换同步RestAssured为Quarkus响应式Web测试客户端发起非阻塞调用,配合UniAsserter完成断言,不要在测试线程中阻塞等待响应

方案2:允许接口阻塞执行(快速修复)

直接给MyController类或者update方法加上@io.smallrye.common.annotation.Blocking注解,标记该接口所有逻辑运行在工作线程,即可绕过IO线程阻塞检测。该方案改动最小,但不符合响应式应用全链路非阻塞的设计目标。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 23:06:06