如何让WebSocket的modifyHandshake方法运行在工作线程?
问题描述
实现ServerEndpointConfig.Configurator并重写modifyHandshake处理WebSocket握手逻辑,方法内包含阻塞代码(如Thread.sleep(3000)),但该方法始终运行在Vert.x IO线程中,触发阻塞警告。尝试配置quarkus.websocket.dispatch-to-worker=true仅对@ServerEndpoint的@OnOpen方法生效;给modifyHandshake添加@Blocking注解也无法将其切换到工作线程执行。
复现代码
public class WebSocketEndpointConfigurator extends ServerEndpointConfig.Configurator { @Override public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) { // 阻塞代码示例 try { Thread.sleep(3000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }
报错日志
WARN [io.vertx.core.impl.BlockedThreadChecker] (vertx-blocked-thread-checker) Thread Thread[vert.x-eventloop-thread-7,5,main] has been blocked for 128597346 ms, time limit is 2000 ms: io.vertx.core.VertxException: Thread blocked
解决方案
1. 手动将阻塞逻辑提交到工作线程
由于modifyHandshake不受@Blocking或现有配置的线程调度控制,需手动将阻塞代码委托给Quarkus工作线程池执行。使用VertxContextSupport调度任务,并通过同步等待确保握手逻辑完成:
import io.quarkus.vertx.VertxContextSupport; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; public class WebSocketEndpointConfigurator extends ServerEndpointConfig.Configurator { @Override public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) { CountDownLatch latch = new CountDownLatch(1); VertxContextSupport.subscribeBlocking( () -> { try { // 执行阻塞操作 Thread.sleep(3000); // 将处理结果存入config,供后续端点方法使用 config.getUserProperties().put("handshakeData", "processed"); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { latch.countDown(); } }, false ); try { // 设置超时,避免请求长时间挂起 if (!latch.await(5, TimeUnit.SECONDS)) { throw new RuntimeException("Handshake processing timed out"); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException("Handshake interrupted", e); } } }
2. 升级Quarkus版本(推荐)
Quarkus 2.4.1.Final为旧版本,后续LTS版本(如2.13.x及以上)优化了WebSocket Configurator的线程调度逻辑,@Blocking注解可能会对modifyHandshake生效,或提供了专门的配置项控制该方法的执行线程池。
注意事项
- 禁止在Vert.x IO线程中执行任何阻塞操作,会严重降低应用并发处理能力。
- 手动调度任务时需合理设置超时时间,防止握手请求长时间占用连接资源。
内容的提问来源于stack exchange,提问作者spaykit

