Description
We need to do some work whenever a client websocket is closed.
We tried to use afterConnectionClosed(WebSocketSession, CloseStatus)
inside GraphQlWebSocketHandler
, but it only works if disconnected though messages, not if the TCP connection is closed.
We were able to do it wrapping GraphQlWebSocketHandler
:
@Bean
public GraphQlWebSocketHandler graphQlWebSocketHandler(WebGraphQlHandler webGraphQlHandler,
GraphQlProperties properties, ServerCodecConfigurer configurer) {
return new MyHandler(webGraphQlHandler, configurer,
properties.getWebsocket().getConnectionInitTimeout());
}
And then adding this:
class MyHandler extends GraphQlWebSocketHandler {
public MyHandler(WebGraphQlHandler graphQlHandler, ServerCodecConfigurer configurer,
Duration connectionInitTimeout) {
super(graphQlHandler, configurer, connectionInitTimeout);
}
@Override
public Mono<Void> handle(WebSocketSession session) {
log.info("Handle websocket session");
return super.handle(session).then().doFinally(v -> {
log.info("Finished websocket session");
//Some work
});
}
}
This is ok, just would be great if added to documentation.
Still, we have the problem of identifying the connection. Here we have websocket connection id and handshakeInfo, but nothing about content (that's ok, this is not the place).
What we did was to add a query param to /subscription, so we can have that information inside handshakeInfo
in MyHandler
:
String clientId = util.getQueryParam(session.getHandshakeInfo().getUri().getQuery()).get("clientId");
That way, we can correlate session closed with a specific client. Still, this is a very unclean trick.
I think the right place should be on connection_init
payload and I've seen WebSocketInterceptor
that can read this information. But there is no way to pass that information to previous custom handler. I've also checked handleConnectionCompletion
method, but it's not triggered when TCP connection is suddenly closed.
Would it be possible to create a handler that is also called whenever the websocket connection is closed? We would also need to have some context information within this method (connection_init
payload at least).
Another solution could be to add websocket session id inside WebInput
and also pass WebInput
to handleConnectionInitialization
in WebsocketInterceptor
. This way we could correlate payload information with session Id, which is accesible inside GraphQlWebSocketHandler
.
It's a little bit tricky. I hope it's understandable.