扩展中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
相关产品推荐
相关产品推荐

