I have embedded Jetty 10 and Spring 5.3.37 (non-spring boot) application on it.
While integrating WS server (non-sockjs/stomp) into the application I faced the idle timeout issue, it's too short for my needs and i wanted to increase it but couldn't find a way.
The official Spring documentation has an article on the WebSocket API.
It says that it's possible to configure idle timeout using JettyRequestUpgradeStrategy.addWebSocketConfigurer.
But i guess, it's valid only for recent versions of Spring 6+ and Jetty 11+.
The thing is that I'm using Jetty 10 and Jetty10RequestUpgradeStrategy.
Spring 5's JettyRequestUpgradeStrategy
won't work due to Jetty's 10 WebAppClassLoader restrictions (only for Jetty <= 9).
Jetty10RequestUpgradeStrategy
looks pretty much different and doesn't have anything for customization.
An empty constructor without WebSocketPolicy
and WebSocketServerFactory
unlike the JettyRequestUpgradeStrategy
.
My WS configuration:
@Configuration
@EnableWebSocket
public class WSConfig implements WebSocketConfigurer
{
private final WSNotifyHandler wsNotifyHandler;
public WSConfig(WSNotifyHandler wsNotifyHandler) {
this.wsNotifyHandler = wsNotifyHandler;
}
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(mapWsHandler, "/ws")
.addInterceptors(new HttpSessionHandshakeInterceptor()).setHandshakeHandler(handshakeHandler());
}
@Bean
public DefaultHandshakeHandler handshakeHandler() {
return new DefaultHandshakeHandler(
new Jetty10RequestUpgradeStrategy());
}
}
So far I've run out of ideas on how to work around this issue without migrating to newer versions or "pinging" connection.
Is there a way to configure JettyWebSocketServerContainer
that i missed out?
With my combination of Jetty 10 & Spring 5 it was impossible to do this directly.
Switching to Jetty 12 won't help either due to the lack of necessary API for Jetty 12 in Spring 5.
Moreover, Spring 6's baseline was set to Java 17 & EE9+.
So, my final solution was to finally move to Jetty 12 and upgrade the app to Spring 6 and EE10.
Meanwhile, i quickly dug out a very dirty solution for Jetty 10 that involves reflection and is generally discouraged to use:
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception
{
final var nativeSessionFld = AbstractWebSocketSession.class.getDeclaredField("nativeSession");
nativeSessionFld.setAccessible(true);
final var nativeSessionObj = nativeSessionFld.get(session);
final var setIdleTimeout = nativeSessionObj.getClass().getDeclaredMethod("setIdleTimeout", Duration.class);
setIdleTimeout.invoke(nativeSessionObj, Duration.ofMinutes(2));
}