Description
Back in 528 it was said that:
There is also a more global WebSocketGraphQlInterceptor that lets you be notified when a connection is closed, and/or when a subscription is cancelled.
But in case of websocket connection timing out on a server side, webSocketGraphQlInterceptor.handleConnectionClosed
is not invoked. Relevant exception:
org.eclipse.jetty.websocket.api.exceptions.WebSocketTimeoutException: Connection Idle Timeout
at org.eclipse.jetty.websocket.common.JettyWebSocketFrameHandler.convertCause(JettyWebSocketFrameHandler.java:541)
at org.eclipse.jetty.websocket.common.JettyWebSocketFrameHandler.onError(JettyWebSocketFrameHandler.java:259)
at org.eclipse.jetty.websocket.core.internal.WebSocketCoreSession.lambda$closeConnection$2(WebSocketCoreSession.java:284)
at org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:1466)
at org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:1485)
at org.eclipse.jetty.websocket.core.server.internal.AbstractHandshaker$1.handle(AbstractHandshaker.java:212)
at org.eclipse.jetty.websocket.core.internal.WebSocketCoreSession.closeConnection(WebSocketCoreSession.java:284)
at org.eclipse.jetty.websocket.core.internal.WebSocketCoreSession.lambda$sendFrame$7(WebSocketCoreSession.java:519)
at org.eclipse.jetty.util.Callback$3.succeeded(Callback.java:155)
at org.eclipse.jetty.websocket.core.internal.TransformingFlusher.notifyCallbackSuccess(TransformingFlusher.java:197)
at org.eclipse.jetty.websocket.core.internal.TransformingFlusher$Flusher.process(TransformingFlusher.java:154)
at org.eclipse.jetty.util.IteratingCallback.processing(IteratingCallback.java:243)
at org.eclipse.jetty.util.IteratingCallback.iterate(IteratingCallback.java:224)
at org.eclipse.jetty.websocket.core.internal.TransformingFlusher.sendFrame(TransformingFlusher.java:77)
at org.eclipse.jetty.websocket.core.internal.WebSocketCoreSession.sendFrame(WebSocketCoreSession.java:522)
at org.eclipse.jetty.websocket.core.internal.WebSocketCoreSession.close(WebSocketCoreSession.java:239)
at org.eclipse.jetty.websocket.core.internal.WebSocketCoreSession.processHandlerError(WebSocketCoreSession.java:371)
at org.eclipse.jetty.websocket.core.internal.WebSocketConnection.onIdleExpired(WebSocketConnection.java:242)
at org.eclipse.jetty.io.AbstractEndPoint.onIdleExpired(AbstractEndPoint.java:407)
at org.eclipse.jetty.io.IdleTimeout.checkIdleTimeout(IdleTimeout.java:170)
at org.eclipse.jetty.io.IdleTimeout.idleCheck(IdleTimeout.java:112)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
at java.base/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: org.eclipse.jetty.websocket.core.exception.WebSocketTimeoutException: Connection Idle Timeout
... 11 common frames omitted
I suspect, that happens because GraphQlWebSocketHandler
's handleTransportError
method ( removing the session from the sessionInfoMap) is called before afterConnectionClosed
.
See source code:
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) {
String id = session.getId();
SessionState state = this.sessionInfoMap.remove(id);
if (state != null) {
state.dispose();
Map<String, Object> connectionInitPayload = state.getConnectionInitPayload();
if (connectionInitPayload != null) {
this.webSocketGraphQlInterceptor.handleConnectionClosed(
state.getSessionInfo(), closeStatus.getCode(), connectionInitPayload);
}
}
}
I'm wondering is this intentional that handleConnectionClosed
is not called in case of idle connection is closed? If yes, what should one do to actually be notified about connection closure?
If no, what would be an appropriate fix or workaround for that? One straightforward workaround would be to override methods of GraphQlWebSocketHandler and handle session closure there, WDYT?
Thinking of a proper fix, does transport error always results in a connection getting closed? If yes, then the session removal from sessionInfoMap could be done only in afterConnectionClosed
method?