Quarkus WebSockets使用虚拟线程报错,是否不支持该特性?
这并不代表Jakarta或Quarkus的WebSockets不支持虚拟线程,问题出在**@RunOnVirtualThread注解的生效逻辑**以及当前代码的执行路径上。
核心原因
Quarkus的WebSockets底层基于Vert.x实现,默认会在事件循环线程处理WebSocket生命周期事件(比如@OnOpen),而事件循环线程严格禁止阻塞操作(比如你调用的.await().indefinitely())。你添加的@RunOnVirtualThread注解没有正确将方法调度到虚拟线程执行,导致代码仍然跑在事件循环线程上,触发了阻塞报错。
解决方法
确保Quarkus版本达标
至少使用Quarkus 3.2及以上版本,该版本开始完善了对Jakarta WebSocket生命周期方法的虚拟线程支持。正确标注@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(); } }会话操作的线程注意事项
如果在虚拟线程中需要操作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

