0

I'm making a chatting server with Spring Boot now, and the server works like this.

  1. When a client sends a message to the server,

  2. then the server sends the message to the message broker(Google Cloud PubSub).

  3. After taking the message from the message broker,

  4. the server sends the message to the subscribing clients.(convertAndSend)

1, 2, 3 always work by the logs.

But sometimes 4 works, and sometimes it doesn't. It works about once in two.

I don't know if the server is the problem or the client is the problem. Because there is no error or exception in the logs. I can't trace the method convertAndSend...

Here is my code.

Server Side

    @Component
    class PubSubBean(private val messagingTemplate : SimpMessagingTemplate) {
    // Create a message channel for messages arriving from the subscription `chat-sub`.
    @Bean
    fun inputMessageChannel(): MessageChannel? {
        return PublishSubscribeChannel()
    }

    @Bean
    fun outputMessageChannel(): MessageChannel? {
        return PublishSubscribeChannel()
    }

    // Create an inbound channel adapter to listen to the subscription `chat-sub` and send
    // messages to the input message channel.
    @Bean
    fun inboundChannelAdapter(
        @Qualifier("inputMessageChannel") messageChannel: MessageChannel?,
        pubSubTemplate: PubSubTemplate?
    ): PubSubInboundChannelAdapter? {
        val adapter = PubSubInboundChannelAdapter(pubSubTemplate, "chat-sub")
        adapter.outputChannel = messageChannel
        adapter.ackMode = AckMode.MANUAL
        adapter.payloadType = String::class.java
        return adapter
    }

    // Define what happens to the messages arriving in the message channel.
    @ServiceActivator(inputChannel = "inputMessageChannel")
    fun messageReceiver(
        payload: String,
        @Header(GcpPubSubHeaders.ORIGINAL_MESSAGE) message: BasicAcknowledgeablePubsubMessage
    ) {
        val model = Gson().fromJson(payload, ChatMessageToPubSub::class.java)
        println("received message : " + message.pubsubMessage.data.toStringUtf8())
        println(message.pubsubMessage.attributesMap)
        message.ack()
        println("message ack success : " + message.pubsubMessage.data.toStringUtf8())
        messagingTemplate.convertAndSend("/sub/message/" + model.roomId.toString(), ChatMessageToClient(model.userId, model.message))
        println("message convertandsend success : " + message.pubsubMessage.data.toStringUtf8())
        //LOGGER.info("Message arrived via an inbound channel adapter from chat-sub! Payload: $payload")
    }

    // Create an outbound channel adapter to send messages from the input message channel to the
    // topic `chat`.
    @Bean
    @ServiceActivator(inputChannel = "outputMessageChannel")
    fun messageSender(pubsubTemplate: PubSubTemplate?): MessageHandler? {
        val adapter = PubSubMessageHandler(pubsubTemplate, "chat")
        adapter.setSuccessCallback { ackId, message -> println("send success : " + ackId + " - " + message.payload) }
        adapter.setFailureCallback { cause, message -> println("send fail : " + cause.stackTraceToString() + " - " + message.payload) }
        return adapter
    }
}
@Configuration
@EnableWebSocketMessageBroker
class WebSocketConfig : WebSocketMessageBrokerConfigurer {

    @Autowired
    private lateinit var filterChannelInterceptor: FilterChannelInterceptor

    override fun configureMessageBroker(registry: MessageBrokerRegistry) {
        registry.enableSimpleBroker("/sub") // sub topic
        registry.setApplicationDestinationPrefixes("/pub") // client sends messages to /pub/message
    }

    override fun registerStompEndpoints(registry: StompEndpointRegistry) {
        registry.addEndpoint("/chatting").setAllowedOrigins("*").withSockJS() 
    }

    override fun configureClientInboundChannel(registration: ChannelRegistration) {
        registration.interceptors(filterChannelInterceptor)
    }
}

Client Side

          stompClient = Stomp.over(new SockJS(endPoint));
                    stompClient.connect(headers, function (frame) {
                        console.log("connected: " + frame);
                        stompClient.subscribe("/sub/message/" + roomId, function (response) {
                            var datum = JSON.parse(response.body);
                            console.log(datum)
                        }, headers);
sendBtn.addEventListener("click", function(){
    var chat = JSON.stringify({
        message: document.querySelector("#typeMessage").value,
    });
    console.log("send message : " + chat)
    stompClient.send("/pub/message/" + roomId, {Authorization : accessToken}, chat);

    document.querySelector("#typeMessage").value = "";
});

p.s. WebSocket connection is disconnected after exactly 5 minutes from starting the connection. Why is it happened? I tried many times with different conditions, but the disconnection occurs after exactly 5 minutes from starting the connection.

UPDATE : I set the level of the logs as TRACE, and I find out that there is a difference between success and failure of convertAndSend.

When it is successful, the logs are like this. (It's the logs of the demo version)

o.s.m.s.b.SimpleBrokerMessageHandler     : Processing MESSAGE destination=/chat/message session=null payload={"userId":1828,"message":"asdf","roomid":null}
o.s.m.s.b.SimpleBrokerMessageHandler     : Broadcasting to 2 sessions.
o.s.messaging.simp.stomp.StompEncoder    : Encoding STOMP MESSAGE, headers={destination=[/chat/message], content-type=[application/json], subscription=[sub-0], message-id=[klcsfv03-1]}

But when it fails, the logs are like this.

o.s.m.s.b.SimpleBrokerMessageHandler     : Processing MESSAGE destination=/chat/message session=null payload={"userId":1828,"message":"asdf","roomid":null}

There is no error and exception after "Processing ~", and the server didn't broadcast the messsage to the sessions when failed.

As I know, convertAndSend sends the message to all the sessions that saved in the memory of the server. I don't know why this happened.

UPDATE 2 : I find out old SO question that is quite similar to my question.

WebSocket message not broadcast when sent by spring integration method

But there was only one simpleBrokerMessagingHandler instance when I checked my server.

kimurzzoo
  • 11
  • 3

0 Answers0