8

Używam PostgreSQL DB i stosowanie jego funkcji LISTEN/NOTIFY. Tak więc mój słuchacz jest na moim AS (Application Server) i mam wyzwalacze skonfigurowane na moim DB tak, że gdy operacje CRUD są wykonywane na stole, żądanie NOTIFY jest wysyłane na AS.LISTEN/NOTIFY pgconnection idzie w dół java?

słuchacz klasa w Javie:

 @Singleton 
     @Startup 
    NotificationListenerInterface.class) 
     public class NotificationListener extends Thread implements NotificationListenerInterface { 

      @Resource(mappedName="java:/RESOURCES") 
      private DataSource ds; 

      @PersistenceContext(unitName = "one") 
      EntityManager em; 

      Logger logger = Logger.getLogger(NotificationListener.class); 

      private Connection Conn; 
      private PGConnection pgConnection = null; 
      private NotifyRequest notifyRequest = null; 

      @PostConstruct 
      public void notificationListener() throws Throwable { 

       System.out.println("Notification****************"); 
       try 
       { 


        Class.forName("com.impossibl.postgres.jdbc.PGDriver"); 
        String url = "jdbc:pgsql://192.xx.xx.126:5432/postgres"; 


        Conn = DriverManager.getConnection(url,"postgres","password"); 
        this.pgConnection = (PGConnection) Conn; 

        System.out.println("PG CONNECTON: "+ pgConnection); 
        Statement listenStatement = Conn.createStatement(); 
        listenStatement.execute("LISTEN notify_channel"); 
        listenStatement.close(); 

        pgConnection.addNotificationListener(new PGNotificationListener() { 

         @Override 
         public void notification(int processId, String channelName, String payload){ 

          System.out.println("*********INSIDE NOTIFICATION*************"); 

          System.out.println("Payload: " + jsonPayload); 

} 

Tak jak mój AS jest gotowy, mam skonfigurowany, że przy starcie klasa słuchacz nazywa (@Startup annotation) i to zacząć słuchać na kanale.

Teraz działa dobrze, jeśli chcesz powiedzieć, że do testowania Edytuję moją tabelę w DB ręcznie, generowane jest powiadomienie, a LISTENER je otrzymuje.

Jednak, gdy programowo wysyłam żądanie aktualizacji na stole, UPADTE jest wykonywane pomyślnie, ale LISTENER nic nie otrzymuje.

Uważam, że moje połączenie z LISTENERÓW przestaje działać, gdy wysyłam żądanie (to także tworzy połączenie z podmiotami edycji), ale nie jestem pewien. Czytałem o stałych połączeniach i połączonych połączeniach, ale nie byłem w stanie zdecydować, jak tego dokonać.

Używam słoika pgjdbc (http://impossibl.github.io/pgjdbc-ng/) do powiadomień asynchronicznych, ponieważ połączenie jdbc wymaga sondowania.

EDIT:

Gdy próbuję powyższy słuchacza odpytywania za pomocą standardowego jdbc słoik (nie pgjdbc), otrzymuję powiadomień.

Mam i otrzymuję powiadomienia, jednak wykonuję to asynchronicznie, jak poniżej, nie otrzymuję powiadomień.

pgConnection.addNotificationListener(new PGNotificationListener() { 

     @Override 
     public void notification(int processId, String channelName, String payload){ 

      System.out.println("*********INSIDE NOTIFICATION*************"); 
     } 

rozwiązany:

Mój słuchacz jechał z zakresu po wykonaniu funkcja została zakończona, jak mój słuchacz miał zakres funkcji. Zatrzymałem go więc w zmiennej członkowskiej mojej klasy komponentu bean, a następnie zadziałało.

+0

Wewnątrz odbiornika zmienna "jsonPayload" nie istnieje. Czy używasz tego samego połączenia do pisania swoich aktualizacji?Możliwe jest, że twoje połączenie z dołączonym słuchaczem wykracza poza zakres i jest niszczone przez GC. –

+0

Nie używam tego samego połączenia. Ale sprawdziłem przy użyciu 'netstat', że połączenia były w stanie ustalonym, tzn. Stare połączenie nie zostało utracone. 'netstat -numeric-ports | grep 5432 | grep my.ip' dał dwa połączenia (jeden stary i jeden nowy) i oba w stanie ESTABLISHED:' tcp 0 0 192.168.5.126:5432 192.168.105.213:46802 ESTABLISHED tcp 0 0 192.168.5.126:5432 192.168.105.213:46805 ESTABLISHED' –

+0

@ LukeA.Leber: Sprawdź edycję na pytanie. –

Odpowiedz

5

Słuchacze z powiadomieniami są wewnętrznie obsługiwani przez tę bibliotekę jako słabe referencje, co oznacza, że ​​trzeba przechowywać twarde odwołanie na zewnątrz, aby nie były zbierane śmieci. Sprawdź linii klasy BasicContext 642 - 655:

public void addNotificationListener(String name, String channelNameFilter, NotificationListener listener) { 

    name = nullToEmpty(name); 
    channelNameFilter = channelNameFilter != null ? channelNameFilter : ".*"; 

    Pattern channelNameFilterPattern = Pattern.compile(channelNameFilter); 

    NotificationKey key = new NotificationKey(name, channelNameFilterPattern); 

    synchronized (notificationListeners) { 
     notificationListeners.put(key, new WeakReference<NotificationListener>(listener)); 
    } 

} 

Jeśli GC podnosi swoją słuchacza, nazywa się „dostać” na słabego odniesienia powróci nieważne i nie zadziała, jak wynika z linii 690 - 710

@Override 
    public synchronized void reportNotification(int processId, String channelName, String payload) { 

    Iterator<Map.Entry<NotificationKey, WeakReference<NotificationListener>>> iter = notificationListeners.entrySet().iterator(); 
    while (iter.hasNext()) { 

     Map.Entry<NotificationKey, WeakReference<NotificationListener>> entry = iter.next(); 

     NotificationListener listener = entry.getValue().get(); 
     if (listener == null) { 

     iter.remove(); 
     } 
     else if (entry.getKey().channelNameFilter.matcher(channelName).matches()) { 

     listener.notification(processId, channelName, payload); 
     } 

    } 

} 

Aby rozwiązać ten problem, należy dodać słuchaczy powiadomień jako takie:

/// Do not let this reference go out of scope! 
PGNotificationListener listener = new PGNotificationListener() { 

@Override 
public void notification(int processId, String channelName, String payload) { 
    // interesting code 
}; 
pgConnection.addNotificationListener(listener); 

dość dziwny przypadków użycia dla słabych referencji moim zdaniem ...

+0

Dzięki, uratowałeś mi dzień. Byłem bardzo zdezorientowany – sanket1729

Powiązane problemy