alvinmeimoun
alvinmeimoun

Reputation: 1540

Stomp not receiving CONNECTED frame (Angular + Spring)

I'm currently implementing a backend to frontend message mechanism using SockJS and Stomp on my Spring Boot 2 + Angular 14 app

I get a random behaviour, sometimes everythings works, but sometimes the websocket doesn't receive any messages.

When it doesn't work, WS messages looks like this

no connected frame

But when it works

connected and subscribe frame

The main difference is that when it workds, it receive a CONNECTED frame and fire the subscription. I don't get why sometimes it doesn't receive the CONNECTED frame.

My backend configuration

@Configuration
@EnableWebSocketMessageBroker
class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry
            .addEndpoint("/socket/no")
            .setAllowedOriginPatterns("*").withSockJS();
    }
}

The frontend client (app.component.ts > ngOnInit)

    const socketUrl = `${window.origin}/socket/no`;
    const stompClient = new Client({
      brokerURL: socketUrl,
      connectHeaders: {},
      debug: function (str) {
        console.debug(str);
      },
      reconnectDelay: 5000,
      webSocketFactory: function () {
        return new SockJS(socketUrl);
      },
      onConnect: function () {
        stompClient.subscribe("/topic/no", function (msg) {
          console.log("message received");
        });
      },
    });

    stompClient.activate();
  

proxy.conf.json

"/socket/**": {
        "target": "http://localhost:8080",
        "secure": false,
        "ws": true
    },

I feel like it's more likely to work when i open the angular app on a small page. For example my homepage has a lot of component and take some time to load. But when i open the app with the url of a simple grid view it has more chance to work but not all times.

Due to this feeling, i think it's a frontend issue. Maybe a required angular component for websocket not loader or something like this.

On the backend side i see this log after the connect frame sent

ms.w.s.h.LoggingWebSocketHandlerDecorator New WebSocketServerSockJsSession[id=naeygmcp]

Upvotes: 1

Views: 2371

Answers (3)

alvinmeimoun
alvinmeimoun

Reputation: 1540

Finally, migrating from Spring Boot 2.4 to 2.7 solved the issue. Now my app is migrated to Spring Boot 3.0 since some month and the issue didn't came back

Looks related to this https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-22971

Upvotes: 0

alvinmeimoun
alvinmeimoun

Reputation: 1540

I moved the client initialization from ngOnInit to ngAfterViewInit and it seems to work now.

I will continue to test this solution some days before marking this answer as accepted


EDIT : It was not the root cause of the problem

Upvotes: 0

CH Liu
CH Liu

Reputation: 1884

Your WebSocket thread pool might be exhausted. By default, the thread pool is configured with:

core pool size = CORE * 2
max pool size  = CORE * 2
queue capacity = Integer.MAX_VALUE

A successful connected STOMP client will go through the following stages:

  1. Establishes a WebSocket connection (HTTP status: 101)
  2. Sends a STOMP command CONNECT
  3. Receives a STOMP command CONNECTED
  4. Sends a STOMP command SUBSCRIBE
  5. Sends a STOMP command SEND

The 1st one is just an HTTP request, so it won't use that thread pool. On the contrary, the remaining stages under STOMP protocol will all use the pool. Maybe there are some long-running requests in your app occupying the pool, causing clients stuck at the second stage.

A possible solution is adjust that pool:

@Configuration
@EnableWebSocketMessageBroker
public class DefaultWebSocketMessageBrokerConfigurer implements WebSocketMessageBrokerConfigurer {
    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration
                .taskExecutor()
                .corePoolSize(8)
                .maxPoolSize(512)
                .queueCapacity(32)
                .keepAliveSeconds(30);
    }
}

Upvotes: 1

Related Questions