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

Quarkus Reactive Websocket Hibernate查询RequestScoped未激活

问题现象

在Quarkus Websocket的@OnMessage处理逻辑中执行响应式Hibernate Panache查询时,响应式调用无报错直接失败,使用.await().indefinitely()阻塞获取结果时捕获到如下异常:

Exception in thread "Thread-752" java.util.concurrent.CompletionException: javax.enterprise.context.ContextNotActiveException: RequestScoped context was not active when trying to obtain a bean instance for a client proxy of PRODUCER_METHOD bean [class=io.quarkus.hibernate.reactive.runtime.ReactiveSessionProducer, id=404040404040]
    - you can activate the request context for a specific method using the @ActivateRequestContext interceptor binding

按照提示给方法添加@ActivateRequestContext注解、尝试Panache.withTransaction、注入Mutiny.SessionFactory执行查询均无法解决问题,复现代码如下:

@OnMessage
@ActivateRequestContext
public void onMessage(Session session, String message) {
   // websocket线程不可被阻塞
   new Thread(() -> {
      System.out.println(MyHibernateEntity.findAll().firstResult().await().indefinitely());
   }).start();
}
根本原因
  • 手动通过new Thread()创建的线程完全脱离Quarkus CDI容器管控,@ActivateRequestContext是CDI拦截器注解,仅对CDI容器代理调用的Bean方法生效,手动启动的自定义线程不会自动激活、传播请求上下文,即使把查询逻辑拆分到带注解的单独方法中,只要调用方是手动创建的非受管线程,拦截器就不会生效。
  • 响应式Panache的Session绑定在请求上下文上,脱离受管上下文后自然无法获取到Session实例,这也是尝试Panache.withTransaction、手动注入SessionFactory执行查询依然失败的核心原因——事务、Session都依赖CDI请求上下文。
  • 自定义线程中调用.await().indefinitely()属于错误的响应式用法,会直接阻塞线程,同时打断响应式上下文的传播链路。
修复方案

推荐方案:使用容器受管的执行器+非阻塞链式调用

不要手动创建线程,注入Quarkus自带的支持上下文传播的ManagedExecutor,全程使用响应式链式处理,不要用阻塞式的await()方法:

import io.quarkus.vertx.ManagedExecutor;
import jakarta.websocket.OnMessage;
import jakarta.websocket.Session;
import jakarta.inject.Inject;

@Inject
ManagedExecutor managedExecutor;

@OnMessage
public void onMessage(Session session, String message) {
    MyHibernateEntity.findAll().firstResult()
        // 把数据库操作切换到受管工作线程执行,避免阻塞Websocket事件循环
        .emitOn(managedExecutor)
        .subscribe().with(
            result -> {
                // 处理查询结果
                System.out.println(result);
                // 可在此处通过session对象返回响应消息
            },
            error -> {
                // 处理异常
                error.printStackTrace();
            }
        );
}

这种方式不需要额外加@ActivateRequestContext,受管执行器会自动传播、激活所需的请求上下文,Panache可以正常获取到Reactive Session实例。

手动控制请求上下文方案(非必要不推荐)

如果确实需要在非受管线程中执行操作,可以注入RequestContextController手动激活/关闭请求上下文:

import jakarta.enterprise.context.control.RequestContextController;
import jakarta.inject.Inject;

@Inject
RequestContextController requestContextController;

// 在自定义线程的执行逻辑中调用
public void runQueryInCustomThread() {
    boolean isActivated = requestContextController.activate();
    try {
        // 在此处执行Panache查询
        MyHibernateEntity.findAll().firstResult().await().indefinitely();
    } finally {
        if (isActivated) {
            requestContextController.deactivate();
        }
    }
}

注意:Websocket的@OnMessage方法默认运行在Vert.x事件循环线程上,绝对禁止在事件循环线程上执行任何阻塞操作(包括.await().indefinitely()、阻塞式IO等),否则会触发Vert.x事件循环阻塞告警,严重影响服务性能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 03:45:34