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

扩展中AsyncHealthCheck使用异常问题求助

问题描述

在Quarkus扩展中使用AsyncHealthCheck时触发阻塞错误:实现的CoreApiHealthCheck类调用返回Uni类型的oqmCoreApiClient.getApiServerHealth()方法,在map操作内使用await().indefinitely()时抛出错误The current thread cannot be blocked: vert.x-eventloop-thread-0。使用quarkus-rest-client-reactive依赖,调用/q/health接口返回状态为DOWN,错误信息如上。

健康检查类代码

@Readiness
@ApplicationScoped
public class CoreApiHealthCheck implements AsyncHealthCheck {
    @RestClient
    OqmCoreApiClientService oqmCoreApiClient;
    @Override
    public Uni<HealthCheckResponse> call() {
        HealthCheckResponseBuilder responseBuilder = HealthCheckResponse.named("OqmCoreApi");
        return this.oqmCoreApiClient.getApiServerHealth()
                   .map((ObjectNode coreApiHealth) -> {
                       ObjectNode returned = this.oqmCoreApiClient.getApiServerHealth().await().indefinitely();
                       String status = returned.get("status").asText();
                       if(status.equalsIgnoreCase(HealthCheckResponse.Status.UP.name())){
                           responseBuilder.up();
                       } else {
                           responseBuilder.down();
                       }
                       return responseBuilder.build();
                   })
                   .onFailure().recoverWithItem(e -> {
                       return responseBuilder.down().withData("error", e.getMessage()).build();
                   });
    }
}

测试类代码

public class CoreApiLibHealthCheckTest {
    @RegisterExtension
    static final QuarkusUnitTest config = new QuarkusUnitTest()
                                              .withEmptyApplication()
                                                  .overrideConfigKey("quarkus."+Constants.CONFIG_ROOT_NAME + ".health.enabled", "true");
    @Test
    public void testDataSourceHealthCheckExclusion() {
        ValidatableResponse response = RestAssured.when().get("/q/health")
            .then();
        System.out.println(response.extract().body().asPrettyString());
        response.statusCode(200)
            .body("status", CoreMatchers.equalTo("UP"));
    }
}

错误响应

{
    "status": "DOWN",
    "checks": [
        {
            "name": "OqmCoreApi",
            "status": "DOWN",
            "data": {
                "error": "java.lang.IllegalStateException - The current thread cannot be blocked: vert.x-eventloop-thread-0"
            }
        }
    ]
}

解决方案

1. 修复健康检查类的响应式代码错误

问题核心原因:

  • map操作运行在Vert.x EventLoop线程上,该线程严格禁止阻塞操作(比如await().indefinitely())
  • 重复调用getApiServerHealth()完全多余,map参数已经提供了请求结果

修改后的健康检查类代码:

@Readiness
@ApplicationScoped
public class CoreApiHealthCheck implements AsyncHealthCheck {
    @RestClient
    OqmCoreApiClientService oqmCoreApiClient;

    @Override
    public Uni<HealthCheckResponse> call() {
        HealthCheckResponseBuilder responseBuilder = HealthCheckResponse.named("OqmCoreApi");
        return oqmCoreApiClient.getApiServerHealth()
                .map(coreApiHealth -> {
                    String status = coreApiHealth.get("status").asText();
                    if (HealthCheckResponse.Status.UP.name().equalsIgnoreCase(status)) {
                        responseBuilder.up();
                    } else {
                        responseBuilder.down();
                    }
                    return responseBuilder.build();
                })
                .onFailure().recoverWithItem(e -> 
                    responseBuilder.down().withData("error", e.getMessage()).build()
                );
    }
}

2. 确保测试环境使用响应式模式

QuarkusUnitTest默认支持响应式环境,只需注意两点:

  • 确保测试依赖包含quarkus-rest-client-reactive和quarkus-smallrye-health相关测试包(通常通过引入quarkus-smallrye-health-deployment或直接声明对应依赖)
  • AsyncHealthCheck本身就是为响应式场景设计的,无需额外配置即可启用响应式健康检查

测试类优化建议(可选)

如果需要模拟Core API的健康响应,避免真实网络请求干扰测试,可添加Mock逻辑:

public class CoreApiLibHealthCheckTest {
    @RegisterExtension
    static final QuarkusUnitTest config = new QuarkusUnitTest()
            .withEmptyApplication()
            .overrideConfigKey("quarkus."+Constants.CONFIG_ROOT_NAME + ".health.enabled", "true")
            .overrideConfigKey("quarkus.rest-client." + OqmCoreApiClientService.class.getName() + "/mp-rest/url", "http://localhost:8080");

    @Mock
    @RestClient
    OqmCoreApiClientService oqmCoreApiClient;

    @Test
    public void testHealthCheckUp() {
        // 模拟健康返回UP
        ObjectNode mockResponse = JsonNodeFactory.instance.objectNode();
        mockResponse.put("status", "UP");
        when(oqmCoreApiClient.getApiServerHealth()).thenReturn(Uni.createFrom().item(mockResponse));

        RestAssured.when().get("/q/health")
                .then()
                .statusCode(200)
                .body("status", CoreMatchers.equalTo("UP"))
                .body("checks[0].name", CoreMatchers.equalTo("OqmCoreApi"))
                .body("checks[0].status", CoreMatchers.equalTo("UP"));
    }

    @Test
    public void testHealthCheckDown() {
        // 模拟健康返回DOWN
        ObjectNode mockResponse = JsonNodeFactory.instance.objectNode();
        mockResponse.put("status", "DOWN");
        when(oqmCoreApiClient.getApiServerHealth()).thenReturn(Uni.createFrom().item(mockResponse));

        RestAssured.when().get("/q/health")
                .then()
                .statusCode(503)
                .body("status", CoreMatchers.equalTo("DOWN"))
                .body("checks[0].status", CoreMatchers.equalTo("DOWN"));
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 04:53:16