У меня есть очередь JMS, опубликованная третьей стороной. Я хочу настроить несколько потребителей на разных машинах, при этом только один конкретный потребитель машины будет подтверждать сообщения в этой очереди. Короче говоря, если потребитель конкретной машины не получает сообщение, то это сообщение не следует удалять из очереди. Это достижимо?
JMS - одна очередь и много получателей (потребителей)
Ответы (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 (). Я не вижу реального смысла в том, чтобы не использовать транзакции. Подтверждение только для того, чтобы гарантировать доставку.
Другой способ взглянуть на это - в случае очереди пересылки. Вы можете применить его к своему дизайну, выполнив следующие действия:
- Создайте потребителя в опубликованной очереди от третьей стороны.
- У этого потребителя одна задача - рассылать каждое сообщение в другие очереди.
- Создайте дополнительные очереди, которые будут слушать ваши настоящие подписчики.
- Запрограммируйте прослушиватель сообщений, чтобы принимать каждое сообщение и пересылать его различным адресатам.
- Измените каждого из ваших слушателей на чтение из их конкретной очереди.
Делая это, вы гарантируете, что каждый слушатель видит каждое сообщение, каждая транзакция работает должным образом, и вы не делаете никаких предположений о том, как отправляется сообщение (например, что, если сторона издателя делает AUTO_ACKNOWLEDGE
?)