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

使用quarkus-keycloak-admin-client-reactive时抛出BlockingNotAllowedException求助

排查Quarkus 3.7.3中BlockingNotAllowedException异常的思路及解决方案

针对你在使用quarkus-keycloak-admin-client-reactive时遇到的异常,以下是具体排查方向和解决方法:

1. 排查依赖冲突

确保项目中仅引入响应式版本的Keycloak Admin Client,避免阻塞版依赖共存:

<!-- 正确依赖 -->
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-keycloak-admin-client-reactive</artifactId>
</dependency>

<!-- 必须移除阻塞版依赖 -->
<!-- <dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-keycloak-admin-client</artifactId>
</dependency> -->

2. 检查配置是否意外启用阻塞模式

确认application.properties中未强制开启阻塞客户端模式:

# 确保该配置不存在或设为false(默认值即为false)
quarkus.keycloak.admin-client.blocking-enabled=false

# 其他基础配置示例
quarkus.keycloak.admin-client.server-url=http://localhost:8080/auth
quarkus.keycloak.admin-client.realm=master
quarkus.keycloak.admin-client.client-id=admin-cli
quarkus.keycloak.admin-client.username=admin
quarkus.keycloak.admin-client.password=admin

3. 检查代码中的阻塞操作

禁止在响应式上下文调用block()/await()

如果在无@Blocking注解的响应式方法(如REST接口)中调用Uni的block()或await(),会直接阻塞事件循环线程触发异常:

// 错误示例
@GET
@Path("/users")
public List<UserRepresentation> getUsers() {
    // 此处调用await()会阻塞事件循环线程
    return keycloak.realm("master").users().list().await().indefinitely();
}

// 正确示例:直接返回Uni,由Quarkus处理响应式流
@GET
@Path("/users")
public Uni<List<UserRepresentation>> getUsers() {
    return keycloak.realm("master").users().list();
}

避免在Uni回调中执行阻塞操作

Uni的onItem().invoke()/onFailure().invoke()等回调默认在事件循环线程执行,若其中包含同步JDBC、文件IO、第三方同步客户端调用等阻塞操作,会触发异常:

// 错误示例:回调中执行阻塞操作
public Uni<Void> createUser(UserRepresentation user) {
    return keycloak.realm("master").users().create(user)
        .onItem().invoke(() -> {
            // 同步JPA持久化属于阻塞操作
            entityManager.persist(new UserLog(user.getUsername()));
        });
}

// 解决方法1:用@Blocking注解标记阻塞方法,Quarkus自动切换到工作线程
public Uni<Void> createUser(UserRepresentation user) {
    return keycloak.realm("master").users().create(user)
        .onItem().invoke(() -> logUserCreation(user.getUsername()));
}

@Blocking
public void logUserCreation(String username) {
    entityManager.persist(new UserLog(username));
}

// 解决方法2:用Uni包装阻塞操作并指定工作线程池
public Uni<Void> createUser(UserRepresentation user) {
    return keycloak.realm("master").users().create(user)
        .onItem().invoke(() -> {
            Uni.createFrom().item(() -> entityManager.persist(new UserLog(user.getUsername())))
                .runSubscriptionOn(Infrastructure.getDefaultWorkerPool())
                .subscribe().with(v -> {});
        });
}

4. 线程上下文调试

若以上排查无效,开启Quarkus调试日志,跟踪异常发生时的线程名称:

  • 事件循环线程名称通常带有vert.x-eventloop-前缀
  • 工作线程名称带有quarkus-worker-前缀

通过线程名称确认阻塞操作是否发生在事件循环线程中,进一步定位代码中的隐性阻塞逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 20:42:23