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

Quarkus使用Reactive RestEasy与GraphQlClient时出现线程阻塞问题

问题根本原因

你当前使用的quarkus-resteasy-reactive组件默认将REST接口运行在非阻塞I/O线程池上,该线程池的线程不允许执行任何阻塞操作。你代码中的entityRepository.createRevision(formData)是调用GraphQL客户端的同步阻塞API,直接在I/O线程执行会导致线程被占满卡住,表现为日志已经打印但实际网络请求没有被调度发送。
你添加@Blocking注解后功能正常,是因为该注解会让接口调度到支持阻塞操作的工作线程池运行,不会占用I/O线程。
你之前将createRevision返回值改为Uni仍然失效,大概率是方法内部依然调用了阻塞API(比如调用GraphQL客户端的同步execute方法,或者使用.block()主动阻塞等待Uni结果),本质还是阻塞了I/O线程。

两种可行解决方案

方案1:保留@Blocking注解(推荐,实现成本最低)

如果你的业务逻辑中本身就存在不可避免的阻塞操作,直接在Controller方法上添加@Blocking注解即可,这是Quarkus官方提供的标准方案,完全符合开发规范,不需要强行改造为全异步流程。

方案2:改造为全响应式非阻塞流程

如果需要保持全异步非阻塞的调用链,需要将GraphQL客户端的调用也改为异步API:

  1. 确认entityRepository.createRevision内部使用SmallRye GraphQL客户端的异步API,比如调用executeUni()而非同步的execute()方法,方法返回Uni<RevisionResponse>,全程不出现任何阻塞操作。
  2. 调整Service层代码,将两段异步逻辑通过响应式操作符串接:
public Uni<DocumentResponse> uploadFile(@NonNull FormData formData) {
    // 异步调用GraphQL创建版本
    return entityRepository.createRevision(formData)
            // 拿到版本结果后执行异步S3上传
            .onItem().transformToUni(revisionResponse -> 
                Uni.createFrom().future(storageProviderFactory.getDefaultStorageProvider().upload(formData))
                    // 上传完成后组装返回对象
                    .map(uploadRes -> DocumentResponse.builder()
                            .id(revisionResponse.getId())
                            .entityMasterId(revisionResponse.getEntityMasterId())
                            .type(revisionResponse.getType())
                            .path(formData.getFilePath())
                            .description(formData.getDescription())
                            .build())
            );
}

核心注意事项

Quarkus响应式模型下,所有非@Blocking标注的方法都运行在I/O线程上,严禁执行任何阻塞操作,包括同步HTTP调用、同步数据库访问、Thread.sleep()、主动调用.block()等待响应式结果等,一旦出现阻塞就会导致线程资源耗尽,请求挂起。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 16:36:03