spring-bootspring-integrationspring-websocket

keeping connection alive to websocket when using ServerWebSocketContainer


I was trying to create a websocket based application where the server needs to keep the connection alive with the clients using heartbeat. I checked the server ServerWebSocketContainer.SockJsServiceOptions class for the same, but could not use it. I am using the code from the spring-integration sample

@Bean
ServerWebSocketContainer serverWebSocketContainer() {
    return new ServerWebSocketContainer("/messages").withSockJs();
}

@Bean
MessageHandler webSocketOutboundAdapter() {
    return new WebSocketOutboundMessageHandler(serverWebSocketContainer());
}

@Bean(name = "webSocketFlow.input")
MessageChannel requestChannel() {
    return new DirectChannel();
}

@Bean
IntegrationFlow webSocketFlow() {
    return f -> {
        Function<Message , Object> splitter = m -> serverWebSocketContainer()
                .getSessions()
                .keySet()
                .stream()
                .map(s -> MessageBuilder.fromMessage(m)
                        .setHeader(SimpMessageHeaderAccessor.SESSION_ID_HEADER, s)
                        .build())
                .collect(Collectors.toList());
        f.split( Message.class, splitter)
                .channel(c -> c.executor(Executors.newCachedThreadPool()))
                .handle(webSocketOutboundAdapter());
    };
}

@RequestMapping("/hi/{name}")
public void send(@PathVariable String name) {
    requestChannel().send(MessageBuilder.withPayload(name).build());
}

Please let me know how can I set the heartbeat options ensure the connection is kept alive unless the client de-registers itself.

Thanks


Solution

  • Actually you got it right, but missed a bit of convenience :-). You can configure it like this:

    @Bean
    ServerWebSocketContainer serverWebSocketContainer() {
        return new ServerWebSocketContainer("/messages")
              .withSockJs(new ServerWebSocketContainer.SockJsServiceOptions()
                                      .setHeartbeatTime(60_000));
    }
    

    Although it isn't clear for me why you need to configure it at all because of this:

    /**
     * The amount of time in milliseconds when the server has not sent any
     * messages and after which the server should send a heartbeat frame to the
     * client in order to keep the connection from breaking.
     * <p>The default value is 25,000 (25 seconds).
     */
    public SockJsServiceRegistration setHeartbeatTime(long heartbeatTime) {
        this.heartbeatTime = heartbeatTime;
        return this;
    }
    

    UPDATE

    In the Spring Integration Samples we have something like stomp-chat application.

    I have done there something like this to the stomp-server.xml:

    <int-websocket:server-container id="serverWebSocketContainer" path="/chat">
        <int-websocket:sockjs heartbeat-time="10000"/>
    </int-websocket:server-container>
    

    Added this to the application.properties:

    logging.level.org.springframework.web.socket.sockjs.transport.session=trace
    

    And this to the index.html:

    sock.onheartbeat = function() {
        console.log('heartbeat');
    };
    

    After connecting the client I see this in the server log:

    2015-10-13 19:03:06.574 TRACE 7960 --- [       SockJS-3] s.w.s.s.t.s.WebSocketServerSockJsSession : Writing SockJsFrame content='h'
    2015-10-13 19:03:06.574 TRACE 7960 --- [       SockJS-3] s.w.s.s.t.s.WebSocketServerSockJsSession : Cancelling heartbeat in session sogfe2dn
    2015-10-13 19:03:06.574 TRACE 7960 --- [       SockJS-3] s.w.s.s.t.s.WebSocketServerSockJsSession : Scheduled heartbeat in session sogfe2dn
    2015-10-13 19:03:16.576 TRACE 7960 --- [       SockJS-8] s.w.s.s.t.s.WebSocketServerSockJsSession : Preparing to write SockJsFrame content='h'
    2015-10-13 19:03:16.576 TRACE 7960 --- [       SockJS-8] s.w.s.s.t.s.WebSocketServerSockJsSession : Writing SockJsFrame content='h'
    2015-10-13 19:03:16.576 TRACE 7960 --- [       SockJS-8] s.w.s.s.t.s.WebSocketServerSockJsSession : Cancelling heartbeat in session sogfe2dn
    2015-10-13 19:03:16.576 TRACE 7960 --- [       SockJS-8] s.w.s.s.t.s.WebSocketServerSockJsSession : Scheduled heartbeat in session sogfe2dn
    

    In the browser's console I see this after:

    enter image description here

    So, looks like heart-beat feature works well...