0

I used Spring Boot to implement a websocket server and a desktop websocket client. The server receives a POJO from the client, performs a calculation with the received data and sends a POJO back.

My problem is that when the response exceeds a certain size the client does not handle it. This appears from the client logs as StandardWebSocketSession[id=29184ecf-687f-19ce-8f8e-d7a9f7284d82, uri=null] closed with CloseStatus[code=1009, reason=The decoded text message was too big for the output buffer and the endpoint does not support partial messages].

I found some discussions on this topic, for example this, or this but none actually fits my scenario or is very old and I am having a difficult time because I would like to implement the correct "state of the art" solution, but I cannot see clearly which and how, since there seem to be a few.

I tried, without success, to increase the size of the buffer to make it large enough for the maximum response I can expect, this size is estimated to be around 500Kb, with the current setup the client can manage a response of about 12 Kb.

The skeleton of the client code is the following:

// STOMP websocket client
    Thread websocketThread = new Thread(() -> {
      WebSocketClient client = new StandardWebSocketClient();
      WebSocketStompClient stompClient = new WebSocketStompClient(client);
      stompClient.setMessageConverter(new MappingJackson2MessageConverter());
      StompSessionHandler sessionHandler = new MsgBrokerWebSocketSessionHandler();

      // Attempt to increase buffer size
      stompClient.setInboundMessageSizeLimit(1024 * 1024);

      CompletableFuture<StompSession> newSession =
          stompClient.connectAsync(SRV_HOST + SRV_PORT + SRV_ENDPOINT, sessionHandler);

      StompSession session = null;

      try {
        session = newSession.get();
        while (true) {
          synchronized (SharedData.getInstance().getDataExchangeMonitor()) {
            SharedData.getInstance().getDataExchangeMonitor().wait();
          }
            session.send(QUERY_DEST, SharedData.getInstance().getQuery());
          }
        }
      } catch (InterruptedException e) {
      } catch (ExecutionException e) {
      }
    });
    websocketThread.setDaemon(true);
    websocketThread.start();
  }

Maybe a better solution would be to send the response in slices, as suggested in the accepted reply of this post, allowing to handle responses of arbitrary size. This could be easily implemented since the largest item in the response data transfer object is an ArrayList<double[]>, so just returning back a limited number of elements of the array would do the job.

My doubt is how to correctly implement sending partial information in my scenario. The desktop client sends the query and the server responds by firing a single call of the respond method in the controller class EngineController. How am I supposed to slice the response? Shall I send back a slice, wait for the client to respond it was received, and then send back the following slice? In a former implementation of this architecture using Django on the server and Java-WebSocket for the client I had absolutely no problem in exchanging Json strings of any size.

My message broker has a real basic configuration:

@Configuration
@EnableWebSocketMessageBroker
public class EngineConfig implements WebSocketMessageBrokerConfigurer {

  @Override
  public void configureMessageBroker(MessageBrokerRegistry config) {
    config.enableSimpleBroker(MSG_BROKER_PREFIX);
    config.setApplicationDestinationPrefixes(APP_DESTINATION_PREFIX);
  }

  @Override
  public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint(SRV_ENDPOINT);
  }

The controller class is also simple

@Controller
public class EngineController {
  @MessageMapping(MSG_DEST)
  @SendTo(RESPONSE_DEST)
  public Response respond(Query query) throws Exception {
    Response response = new Response();
    try {
      Result result = calculate(query);
      response.setStatus("success");
      response.setResult(result);
    } catch (Exception e) {
      response.setStatus("fail");
    }
    return response;
  }
}

Hope this question is not too broad, I am just taking my first steps in Spring boot. Any help is greatly appreciated.

CT95
  • 107
  • 1
  • 11

0 Answers0