I managed to create a WebSocketHandler
using the Spring 5 Reactive WebSocket support (Chapter 23.2.4). Receiving and sending all works fine. However, I can not figure out how to detect a client disconnect. When debugging a client disconnect it somewhere stops at the server side in the HttpServerWSOperations
class (netty.http.server
package), where it does detect a CloseWebSocketFrame
.
Any suggestions how to deal with client disconnects?
I implemented a close event handler in a reactive org.springframework.web.reactive.socket.WebSocketHandler as follows:
public Mono<Void> handle(final WebSocketSession session) {
final String sessionId = session.getId();
if(sessions.add(sessionId)) { // add session id to set to keep a count of active sessions
LOG.info("Starting WebSocket Session [{}]", sessionId);
// Send the session id back to the client
WebSocketMessage msg = session.textMessage(String.format("{\"session\":\"%s\"}", sessionId));
// Register the outbound flux as the source of outbound messages
final Flux<WebSocketMessage> outFlux = Flux.concat(Flux.just(msg), newMetricFlux.map(metric -> {
LOG.info("Sending message to client [{}]: {}", sessionId, metric);
return session.textMessage(metric);
}));
// Subscribe to the inbound message flux
session.receive().doFinally(sig -> {
LOG.info("Terminating WebSocket Session (client side) sig: [{}], [{}]", sig.name(), sessionId);
session.close();
sessions.remove(sessionId); // remove the stored session id
}).subscribe(inMsg -> {
LOG.info("Received inbound message from client [{}]: {}", sessionId, inMsg.getPayloadAsText());
});
return session.send(outFlux);
}
return Mono.empty();
}
The newMetricFlux
field is the source of the outbound websocket messages. The trick to hooking the close event is the doFinally on the inbound message flux. When the websocket client closes, the inbound flux is terminated.
For some reason, though, there is a 1 minute delay between when the netty channel closes and the doFinally
callback is executed. Not sure why yet.
Here's the log output for a browser client connecting and immediately closing. Note the 60 second delay between lines 3 and 4.
2017-08-03 11:15:41.177 DEBUG 28505 --- [ctor-http-nio-2] r.i.n.http.server.HttpServerOperations : New http connection, requesting read
2017-08-03 11:15:41.294 INFO 28505 --- [ctor-http-nio-2] c.h.w.ws.NewMetricsWebSocketHandler : Starting WebSocket Session [87fbe66]
2017-08-03 11:15:48.294 DEBUG 28505 --- [ctor-http-nio-2] r.i.n.http.server.HttpServerOperations : CloseWebSocketFrame detected. Closing Websocket
2017-08-03 11:16:48.293 INFO 28505 --- [ctor-http-nio-2] c.h.w.ws.NewMetricsWebSocketHandler : Terminating WebSocket Session (client side) sig: [ON_COMPLETE], [87fbe66]
Update: October 13, 2017:
As of Spring 5 GA, the delay mentioned above is not present and I observe my callback being invoked immediately after the client is closed. Not sure which version this was fixed in, but as I said, it's fixed in 5.0 GA.