2011-07-14 22 views
7

Abbiamo un'applicazione Java autonoma che esegue qualche elaborazione in background su una macchina Debian. I lavori che deve gestire vengono inviati tramite i messaggi RabbitMQ.Qual è il modo migliore per terminare in modo sicuro un'applicazione java con i consumatori di RabbitMQ in esecuzione

Quando è necessario aggiornare l'applicazione java, è necessario interromperla (ucciderla). Ma dobbiamo essere sicuri che nessun consumatore stia attualmente elaborando un messaggio. Qual è, secondo la tua esperienza, il modo migliore per raggiungere questo obiettivo?

Abbiamo tentato di inviare un messaggio "SHUTDOWN" a un utente, ma non sembra possibile chiudere la coda o il canale ?! Blocca l'applicazione! Oppure esiste un'altra soluzione in cui, ad esempio, è possibile arrestare automaticamente l'applicazione, senza eseguire il comando kill in linux?

Thx per condividere la tua esperienza.

Saluti

+0

È possibile utilizzare i messaggi durevoli e in questo caso si può ucciderlo quando vuoi perché i messaggi in arrivo o in uscita non andranno persi. Questo accoppiamento lento/com asincrono è una delle molte ragioni per cui le persone usano gli MQ. – Shahzeb

+0

@Shahzeb Sì, usiamo messaggi duraturi e per alcuni dei lavori possiamo semplicemente ucciderlo e al riavvio rielabora i messaggi. Ma un particolare lavoro sta facendo un po 'di attività con una API esterna e non deve essere interrotto perché una volta nel processo non è possibile rieseguire la stessa richiesta. –

risposta

2

librerie La RabbitMQ Java non forniscono (per quanto ne so) tutto ciò che posporre automaticamente l'arresto di un processo di consumo, mentre alcuni messaggi sono ancora in fase di elaborazione. Quindi dovrai farlo da solo.

Se la tua applicazione può tollerarlo, basta spegnerlo. Qualsiasi messaggio che non è stato riconosciuto a quel punto rimarrà in coda all'interno del broker e verrà ripresentato quando il consumatore torna a capo.

Se non è possibile tollerare che e si deve assolutamente garantire che tutti in corso di finiture di elaborazione dei messaggi, allora avete bisogno di seguire il consiglio simile a quello che ha trovato in this answer ed effettuare le seguenti operazioni nel gestore di spegnimento:

  1. Impostare un "tutte le discussioni dovrebbero uscire" bandiera a true
  2. Partecipa con ciascuno dei thread nel vostro pool di thread
  3. uscita con grazia

Ciò implica che ciascuno dei vostri thread di elaborazione dei messaggi (ammesso che abbiate più thread di elaborazione dei messaggi contemporaneamente) hanno bisogno di seguire questo schema generale:

  1. tirare un messaggio dalla coda e l'elabora
  2. Ack il messaggio che era appena elaborato
  3. Se i "tutte le discussioni dovrebbero uscire" flag è vero, uscire dalla funzione filo
  4. Risciacquare, ripetere

speranza che aiuta.

+0

Thx per i tuoi approfondimenti. Capisco la teoria, ma il modo in cui usiamo RabbitMQ non creiamo specificamente thread multipli. Tutto è fatto attraverso la creazione di più canali. Quindi non vedo/capisco come potrei implementarlo. Ma continuerò a cercare in base alla tua proposta. Di nuovo. –

+0

Cosa succede se si chiudono tutti i canali all'interno del proprio gestore di spegnimento (oltre ad attendere che tutti i messaggi in corso vengano elaborati come descritto sopra)? Non ti permetterebbe di chiudere con grazia? –

+0

Ciao Brian. Ho trovato una soluzione funzionante. Il tuo post è stato molto utile per questo, ma non sono riuscito a trovare il tempo per postare la soluzione. Spero di poterlo fare questa settimana! –

0

Ecco la mia opinione.

Ho creato la mia sottoclasse di DefaultConsumer (BasicConsumer) che fornisce isCancelled() e implementa handleCancelOk() che imposta un "flag annullato" su true.

sequenza di avvio:

consumers = new ArrayList<BasicConsumer>(); 
consumers.add(...) 

sequenza di arresto:

// Cancel all consumers 
for (BasicConsumer consumer : consumers) { 
    try { 
    consumer.getChannel().basicCancel(consumer.getConsumerTag()); 
    } catch (Exception e) { 
    // report 
    } 
} 

// Wait for all consumers to be cancelled 
Timeout timeout = ...; 
while (!consumers.isEmpty() && !timeout.isElapsed()) { 
    // Remove cancelled consumers 
    for (Iterator<BasicConsumer> iterator = consumers.iterator(); iterator.hasNext();) { 
    if (iterator.next().isCancelled()) 
     iterator.remove(); 
    } 
} 

// Here we could force-close the remaining timed-out consumers if we 
// used our own ExecutorService by shutting down all of its threads. 
connection.close(); 

Rilevante filo RabbitMQ ML: How to shutdown cleanly a Java application using Consumers?

Problemi correlati