JMS - одна очередь и много получателей (потребителей)

У меня есть очередь JMS, опубликованная третьей стороной. Я хочу настроить несколько потребителей на разных машинах, при этом только один конкретный потребитель машины будет подтверждать сообщения в этой очереди. Короче говоря, если потребитель конкретной машины не получает сообщение, то это сообщение не следует удалять из очереди. Это достижимо?


person user1289117    schedule 15.07.2012    source источник
comment
Не знаю, по какой причине, я думал, что все потребители должны получить сообщение, но только один конкретный потребитель подтвердит это сообщение. Если это не так, почему вы хотите иметь несколько потребителей для одной и той же очереди?   -  person Shashi    schedule 16.07.2012


Ответы (2)


Хорошо, у вас могут быть свои причины для такой настройки, и этого легко добиться.

Я бы пошел с транзакциями локального сеанса. Довольно просто зафиксировать или откатить транзакции в соответствии с некоторыми критериями, такими как сервер, получающий сообщение. При откате сообщение снова окажется первым в очереди.

Пример кода может выглядеть так:

public class MyConsumer implements MessageListener{ 
  Session sess;

  public void init(Connection conn, Destination dest){
    // connection and destination from JNDI, or some other method.
    sess = conn.createSession(true, Session.AUTO_ACKNOWLEDGE);
    MessageConsumer cons = sess.createConsumer(dest);
    cons.setMessageListener(this);
    conn.start();
  }

  @Override
  public void onMessage(Message msg) {
    // Do whatever with message
    if(isThisTheSpecialServer()){
       sess.commit();
    }else{
       sess.rollback();
    }
   }

   private boolean isThisTheSpecialServer(){
      // figure out if this server should delete messages or not
   }
}

Если вы делаете это внутри контейнера Java EE с JTA и используете UserTransactions, вы можете просто вызвать UserTransaction.setRollBack (); или если вы используете декларативные транзакции, вы можете просто выбросить исключение времени выполнения, чтобы транзакция завершилась неудачно, и откатить сообщение в очередь после того, как вы прочитали сообщение и сделали что-то. Обратите внимание, что при этом подходе изменения базы данных также будут откатываться (если вы используете JTA, а не локальные транзакции JMS).

ОБНОВИТЬ:

Вы действительно должны делать это, используя транзакции, а не подтверждения.

Краткое изложение этой темы (для ActiveMQ, но написано в основном для JMS) можно найти здесь. http://activemq.apache.org/should-i-use-transactions.html

Я не знаю, согласуется ли это поведение со всеми реализациями JMS, но для ActiveMQ, если вы попытаетесь использовать сеанс без транзакции с Session.CLIENT_ACKNOWLEDGEMENT, тогда он будет вести себя не так, как вы ожидаете. Сообщение, которое было прочитано, но не подтверждено, все еще находится в очереди, но не будет "выпущено" и доставлено другим потребителям JMS до тех пор, пока не будет разорвано соединение с первым потребителем (например, connection.close (), сбой или похожий).

Используя локальные транзакции, вы можете явно контролировать это с помощью session.commit () и session.rollback (). Я не вижу реального смысла в том, чтобы не использовать транзакции. Подтверждение только для того, чтобы гарантировать доставку.

person Petter Nordlander    schedule 15.07.2012
comment
К вашему сведению: откат увеличит JMSXDeliveryCount. Очереди JMS настроены для перемещения сообщений в очередь возврата, когда JMSXDeliveryCount достигает порогового значения. - person Shashi; 16.07.2012
comment
Использование транзакций здесь никоим образом не поможет вам, кроме как убедиться, что вы присоединяетесь к транзакции JTA от начала до конца. - person John Ament; 16.07.2012
comment
Конечно, но порог возврата количества доставок, вероятно, можно настроить (в зависимости от поставщика). Чтобы дать полную картину, остается открытым вопрос. - person Petter Nordlander; 16.07.2012
comment
@JohnAment, конечно, если вы откатываете транзакцию и никакая очередь отката не принимает сообщение, оно станет доступным для других потребителей. Конечно, лучше сделать правильную маршрутизацию сообщений, но полной картины здесь я не вижу. - person Petter Nordlander; 16.07.2012

Другой способ взглянуть на это - в случае очереди пересылки. Вы можете применить его к своему дизайну, выполнив следующие действия:

  1. Создайте потребителя в опубликованной очереди от третьей стороны.
  2. У этого потребителя одна задача - рассылать каждое сообщение в другие очереди.
  3. Создайте дополнительные очереди, которые будут слушать ваши настоящие подписчики.
  4. Запрограммируйте прослушиватель сообщений, чтобы принимать каждое сообщение и пересылать его различным адресатам.
  5. Измените каждого из ваших слушателей на чтение из их конкретной очереди.

Делая это, вы гарантируете, что каждый слушатель видит каждое сообщение, каждая транзакция работает должным образом, и вы не делаете никаких предположений о том, как отправляется сообщение (например, что, если сторона издателя делает AUTO_ACKNOWLEDGE?)

person John Ament    schedule 15.07.2012