0

I am experiencing an odd behavior of my spring boot websocket set-up. Sometimes it works, sometimes it doesn't, it just feels random. I have tried the several setups, none proved solid: I moved the last piece of code in a commandlinerunner inside the primary class of the application and the last choice was a different class with @Component annotation.

My setup is the following: I use a jdbc driver (pgjdbc-ng) to use the listen notify function of postgres.I have a function and a trigger that listens to a specific postgres table for inserations. If any occur, notifications are sent through the websocket. The other and is an angular app that uses ng2-stompjs to listen to /topic/notificari for notifications. I am not posting the code because the notifications don't get out of spring, the angular is not the problem.

Kind regards,

This is my WebSocketConfiguration

Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
    registry.enableSimpleBroker("/topic", "/queue", "/user", "/notificari");
    registry.setApplicationDestinationPrefixes("/app");
    registry.setUserDestinationPrefix("/user");
}

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/socket").setAllowedOrigins("*")
            .setHandshakeHandler(new CustomHandshakeHandler());
}

I am using a class ListenNotify and the JDBC driver pgjdbc-ng to connect to the postgresql db and use listen notify functionality

public class ListenNotify {

private BlockingQueue queue = new ArrayBlockingQueue(20);

PGConnection connection;

public ListenNotify() {


    PGNotificationListener listener = new PGNotificationListener() {
        @Override
        public void notification(int processId, String channelName, String payload) {
            queue.add(payload);
        }
    };

    try {
        PGDataSource dataSource = new PGDataSource();
        dataSource.setHost("localhost");
        dataSource.setDatabase("db");
        dataSource.setPort(5432);
        dataSource.setUser("user");
        dataSource.setPassword("pass");
        connection = (PGConnection) dataSource.getConnection();

        connection.addNotificationListener(listener);

        Statement statement = connection.createStatement();
        statement.execute("LISTEN n_event");
        statement.close();
    } catch (SQLException e) {
        e.printStackTrace();
        }
}

public BlockingQueue getQueue() {
    return queue;
}

}

And finally this is the code that instantiate the ListenNotify object and listens to postgres for events that might trigger notifications that have to be send using websocket.

@Component
public class InstantaNotificari {

@Autowired
SimpMessagingTemplate template;

@EventListener(ApplicationReadyEvent.class)
public void runn() {
    System.out.println("invocare met");
    ListenNotify ln = new ListenNotify();

    BlockingQueue queue = ln.getQueue();

    System.out.println("the que ies "+ queue);

    while (true) {
        try {
            String msg = (String) queue.take();
            System.out.println("msg " + msg);
            template.convertAndSend("/topic/notificari", msg);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

}

gxg
  • 110
  • 2
  • 15

1 Answers1

0

I didn't use Spring so I can't test your code. Here is my tested version. I think this summarizes the differences -

  1. Change to a try with resources block. This will close the connection on destruction of the class.
  2. Move your while(true) into the try block on the Listener so that the lines inside the try block doesn't ever get out of execution scope.
  3. The while(true) is blocking, so it needs to be on another thread. ListenNotify extends Thread

I'm sure there are other ways of implementing and welcome corrections to any of my assumptions.

My tested, running code is in this answer JMS Websocket delayed delivery.

Ted Spradley
  • 3,414
  • 3
  • 22
  • 26