2011-07-14 18 views
7

Tenemos una aplicación java independiente que procesa algunos antecedentes en una máquina Debian. Los trabajos que tiene que manejar se envían a través de mensajes RabbitMQ.¿Cuál es la mejor manera de finalizar de forma segura una aplicación java con clientes RabbitMQ en ejecución?

Cuando la aplicación Java necesita ser actualizada, necesitamos detenerla (matarla). Pero debemos asegurarnos de que ningún consumidor esté procesando un mensaje. ¿Cuál es, en su experiencia, la mejor manera de lograr esto?

Hemos intentado enviar un mensaje 'SHUTDOWN' al consumidor, pero parece que no podemos cerrar la cola o el canal? ¡Congela la aplicación! ¿O existe otra solución en la que podríamos, por ejemplo, apagar automáticamente la aplicación sin ejecutar el comando kill en Linux?

Thx para compartir su experiencia.

Saludos

+0

Puede utilizar mensajes durables y en ese caso se puede matar cuando cada vez que desee porque los mensajes que regresan o salen para ese asunto no se perderán. Ese acoplamiento flojo/com asincrónico es una de las muchas razones por las que las personas usan MQ. – Shahzeb

+0

@Shahzeb Sí, utilizamos mensajes duraderos y para algunos de los trabajos simplemente podemos eliminarlos y al reiniciarlos vuelve a procesar los mensajes. Pero 1 trabajo en particular es hacer negocios con una API externa y no debe interrumpirse porque una vez en el proceso no es posible volver a ejecutarlo en la misma solicitud. –

Respuesta

2

bibliotecas El RabbitMQ Java no proporcionan (que yo sepa) cualquier cosa que posponer automáticamente el cierre de un proceso de consumo, mientras que algunos mensajes están siendo procesados. Por lo tanto, tendrás que hacer esto tú mismo.

Si su aplicación puede tolerarlo, simplemente apague. Cualquier mensaje que no haya sido reconocido en ese momento permanecerá en la cola dentro del intermediario y se volverá a entregar cuando el consumidor vuelva a subir.

Si usted no puede tolerar eso y que es absolutamente necesario garantizar acabados de procesamiento de mensajes que todos en curso, a continuación, es necesario seguir un consejo similar a lo que se encuentra en this answer y hacer lo siguiente en el controlador de apagado:

  1. Establecer una "todas las discusiones deberá tomar la salida" bandera a cierto
  2. Únete con cada uno de los hilos en su grupo de subprocesos
  3. salida con gracia

Esto implica que cada uno de los hilos de procesamiento de mensajes (suponiendo que tiene múltiples hilos de procesamiento mensajes a la vez) es necesario seguir este patrón general:

  1. tirar de un mensaje de la cola y procesarla
  2. Ack el mensaje que era acaba de procesar
  3. Si los "todas las discusiones deben salir" bandera es cierto, salir de la función del hilo
  4. aclara, repite

Espero que ayude.

+0

Thx para sus ideas. Entiendo la teoría pero la forma en que usamos RabbitMQ no crea específicamente múltiples hilos. Todo se hace mediante la creación de múltiples canales. Entonces realmente no entiendo cómo podría implementar esto. Pero continuaré buscando en función de su propuesta. Thx otra vez. –

+0

¿Qué sucede si cierra todos sus canales dentro de su controlador de apagado (además de esperar a que se procesen todos los mensajes en progreso como se describió anteriormente)? ¿No te permitiría eso cerrar con gracia? –

+0

Hola Brian. Encontré una solución de trabajo. Tu publicación fue muy útil para esto, pero no he podido encontrar la hora para publicar la solución. ¡Espero poder hacerlo esta semana! –

0

Aquí está mi opinión sobre esto.

Creé mi subclase de DefaultConsumer (BasicConsumer) que proporciona isCancelled() e implementa handleCancelOk() que establece un "marcador cancelado" en verdadero.

secuencia de inicio:

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

secuencia de parada:

// 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(); 

Relevante hilo RabbitMQ ML: How to shutdown cleanly a Java application using Consumers?

Cuestiones relacionadas