2009-03-09 11 views
14

Quale sarebbe un buon modo per disabilitare temporaneamente un listener di messaggi? Il problema che voglio risolvere è:Come disabilitare temporaneamente un listener di messaggi

  • messaggio A JMS viene ricevuto da un messaggio ascoltatore
  • ottengo un errore quando si cerca di elaborare il messaggio.
  • Attendo che il sistema si riattivi per poter elaborare il messaggio.
  • Fino a quando il mio sistema non è pronto, non voglio altri messaggi, quindi ...
  • ... Voglio disabilitare il listener dei messaggi.
  • Il sistema è di nuovo pronto per l'elaborazione.
  • Il messaggio non riuscito viene elaborato e il messaggio JMS viene riconosciuto.
  • Abilita nuovamente il listener dei messaggi.

In questo momento, sto utilizzando Sun App Server. Ho disabilitato il listener dei messaggi impostandolo su null nel MessageConsumer e abilitato di nuovo usando setMessageListener (myOldMessageListener), ma dopo non ho più ricevuto alcun messaggio.

risposta

14

Cosa succede se non si ritorna dal metodo listener onMessage() finché il sistema non è pronto per elaborare nuovamente i messaggi? Ciò impedirà a JMS di recapitare un altro messaggio su quel consumatore.

Questo è l'equivalente asincrono di non chiamare receive() in un caso sincrono.

Non esiste un multi-threading per una determinata sessione JMS, quindi la pipeline dei messaggi viene mantenuta fino a quando non viene restituito il metodo onMessage().

Non ho familiarità con le implicazioni della chiamata dinamica a setMessageListener(). Javadoc dice there's undefined behavior se chiamato "quando i messaggi vengono consumati da un listener esistente o da un utente di sincronizzazione". Se chiami da onMessage(), sembra che tu stia colpendo quel caso indefinito.

Ci sono i metodi start/stop a livello di Connessione, se questo non è troppo granuloso per voi.

+0

Oh, era davvero così semplice. Mi aspettavo più thread per chiamare il metodo onMessage. Grazie mille! – davidi

+0

Le connessioni sono filettate. Le sessioni in corso (sessioni, consumatori, produttori) non sono thread-safe. Il tuo codice deve evitare l'accesso multithread. Per far ciò, JMS non ha potuto interconnettere le chiamate listener su un solo consumatore. –

+3

Ho appena notato che la specifica JMS specifica esplicitamente questo comportamento di consegna seriale. È la sezione 4.4.16 della specifica JMS 1.0.2. In passato ho pensato che fosse solo implicito dalle regole di threading. –

0

Mi sembra che i messaggi vengano recapitati, ma non succede nulla con loro perché non c'è nessun listener collegato. È passato un po 'di tempo da quando ho fatto qualcosa con JMS, ma non vuoi che il messaggio venga inviato alla coda di messaggi non recapitati o qualcosa del genere mentre correggi il sistema, quindi sposta nuovamente i messaggi sulla coda originale una volta che sei pronto per essere rielaborato?

+0

Questo potrebbe essere ciò che accade. Sfortunatamente, non ho quel controllo del server jms, tutto quello che posso fare è specificare una coda per ricevere messaggi, nessuna coda di messaggi non recapitati. Suppongo che potrei fermare QueueConnection, ma questo non può essere fatto dal thread di messagelistener. – davidi

+0

Come mai non si ha accesso al server JMS. Come giustamente ha fatto notare duffymo, è la coda degli errori a cui vuoi accedere. Altrimenti finirai per replicare il comportamento nel codice che il server JMS ti fornisce. – tddmonkey

+0

Ho quell'accesso al server JMS ... nel mio ambiente di sviluppo, ma non posso aspettarmi che gli utenti dell'applicazione siano lavorando su (un ponte tra due sistemi di messaggistica) hanno le stesse autorizzazioni per il server JMS. Quella lettera morta è la coda del solito modo di affrontare questi problemi? – davidi

0

In WebLogic è possibile impostare un numero massimo di tentativi, una coda di errore per gestire i messaggi che superano il limite massimo di tentativi e altri parametri. Non sono certo fuori di testa, ma potresti anche essere in grado di specificare un periodo di attesa. Tutto questo è a tua disposizione nella console di amministrazione. Guarderei l'amministratore per il provider JMS che hai e vedere se può fare qualcosa di simile.

2

Problema risolto da una soluzione alternativa che sostituisce il listener di messaggi con un ciclo receive(), ma sono ancora interessato a come disabilitare un listener di messaggi e abilitarlo di nuovo a breve.

0

In JBoss il seguente codice farà il trucco:

MBeanServer mbeanServer = MBeanServerLocator.locateJBoss(); 
    ObjectName objName = new ObjectName("jboss.j2ee:ear=MessageGateway.ear,jar=MessageGateway-EJB.jar,name=MessageSenderMDB,service=EJB3"); 
    JMSContainerInvokerMBean invoker = (JMSContainerInvokerMBean) MBeanProxy.get(JMSContainerInvokerMBean.class, objName, mbeanServer); 

    invoker.stop(); //Stop MDB 
    invoker.start(); //Start MDB 
0

penso che si può chiamare

messageConsumer.setMessageListener(null); 

all'interno della vostra implementazione MessageListener e pianificare l'attività di ristabilimento (per esempio in ScheduledExecutorService). Questa attività dovrebbe chiamare

connection.stop(); 
messageConsumer.setMessageListener(YOUR_NEW_LISTENER); 
connection.start(); 

e funzionerà. I metodi start() e stop() sono usati per riavviare gli structrues di consegna (non per la connessione TCP).

Leggi Javadoc https://docs.oracle.com/javaee/7/api/javax/jms/Connection.html#stop--

interrompe temporaneamente la consegna di una connessione di messaggi in arrivo. La consegna può essere riavviata utilizzando il metodo di avvio della connessione. Quando la connessione viene interrotta, la consegna a tutti i consumatori dei messaggi della connessione viene inibita: il blocco riceve sincrono e i messaggi non vengono recapitati ai listener dei messaggi.

0

Per temporaneamente ferma la consegna di una connessione di messaggi in arrivo è necessario utilizzare stop() metodo dal Connection interfaccia: https://docs.oracle.com/javaee/7/api/javax/jms/Connection.html#stop--

Ma non chiamatela connection.stop() da MessageListener perché secondo JMS spec. si otterrà deadlock o eccezione. Invece puoi chiamare connection.stop() da thread diversi, devi solo sincronizzare MessageListener e il thread che va a sospendere la connessione con la funzione connection.stop()

Problemi correlati