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

Quarkus WebSockets使用虚拟线程报错,是否不支持该特性?

Quarkus WebSockets + 虚拟线程问题解答

这并不代表Jakarta或Quarkus的WebSockets不支持虚拟线程,问题出在**@RunOnVirtualThread注解的生效逻辑**以及当前代码的执行路径上。

核心原因

Quarkus的WebSockets底层基于Vert.x实现,默认会在事件循环线程处理WebSocket生命周期事件(比如@OnOpen),而事件循环线程严格禁止阻塞操作(比如你调用的.await().indefinitely())。你添加的@RunOnVirtualThread注解没有正确将方法调度到虚拟线程执行,导致代码仍然跑在事件循环线程上,触发了阻塞报错。

解决方法

  1. 确保Quarkus版本达标
    至少使用Quarkus 3.2及以上版本,该版本开始完善了对Jakarta WebSocket生命周期方法的虚拟线程支持。

  2. 正确标注@RunOnVirtualThread
    必须将@RunOnVirtualThread直接标注在@OnOpen注解所在的方法上,而非类或其他位置。示例:

    @ServerEndpoint("/your-endpoint")
    public class YourWebSocketEndpoint {
        @OnOpen
        @RunOnVirtualThread
        public void onOpen(Session session) {
            // 此方法内代码将在虚拟线程执行
            client.preparedQuery("SELECT * FROM table WHERE id = $1")
                  .execute(Tuple.of(id))
                  .await().indefinitely();
        }
    }
    
  3. 会话操作的线程注意事项
    如果在虚拟线程中需要操作WebSocket会话(比如发送消息),不要直接调用session.getBasicRemote().sendText()这类方法——Vert.x的WebSocket会话操作依赖事件循环线程。你可以通过Quarkus的Vertx实例将会话操作调度回事件循环:

    @Inject
    Vertx vertx;
    
    @OnOpen
    @RunOnVirtualThread
    public void onOpen(Session session) {
        // 阻塞数据库查询在虚拟线程执行
        var result = client.preparedQuery("SELECT * FROM table WHERE id = $1")
                          .execute(Tuple.of(id))
                          .await().indefinitely();
        // 会话操作调度回事件循环
        vertx.runOnContext(v -> {
            try {
                session.getBasicRemote().sendText(result.toString());
            } catch (IOException e) {
                // 处理异常
            }
        });
    }
    

总结

Jakarta WebSocket标准本身不限制虚拟线程的使用,Quarkus也支持在WebSockets中结合虚拟线程处理阻塞任务,只是需要确保版本正确、注解使用方式无误,同时注意会话操作的线程模型要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 21:43:28