Статьи

Отправка отложенных сообщений JMS

Очень часто мне приходилось реализовывать функции, которые должны что-то делать асинхронно за минуту, день или в 5 часов вечера следующего понедельника. Каждый раз, когда я делал это, я реализовывал некоторый механизм сериализации (обычно основанный на БД) и некоторые запланированные задачи, которые периодически запускаются, проверяют таблицу и запускают задачи, которые должны быть выполнены сейчас.

Иногда использовались более общие инструменты, например, Quartz. Я не мог реализовать такие задачи с помощью JMS: причина в том, что JMS API не позволяет отправлять отложенные сообщения, то есть сообщения, которые не будут получены подписчиком или получателем немедленно. Иногда я обнаруживал, что некоторые реализации JMS имеют собственную реализацию для отложенных сообщений. Я решил выполнить некоторые поиски и собрать эту информацию в одном месте. Вот список самых популярных реализаций JMS (см. Википедию ):

  • Apache ActiveMQ
  • Apache Qpid
  • FUSE Message Broker (предприятие ActiveMQ)
  • Mantaray реализация P2P JMS
  • OpenJMS, от группы OpenJMS
  • JBoss Сообщения от JBoss
  • HornetQ от JBoss
  • JORAM от Консорциума OW2
  • Открытая очередь сообщений от Sun Microsystems
  • Системная очередь сообщений Sun Java от Sun Microsystems, поддерживаемая версия Open Message Queue
  • Кролик MQ

Поскольку JMS API не определяет интерфейс для отложенных сообщений, большинство поставщиков SMS, поддерживающих эту функцию, реализовали его с помощью свойств сообщений. Вы просто должны сказать что-то вроде msg.setLongProperty («ЗАДЕРЖКА», задержка) . Некоторые реализации требуют приведения к определенному классу и вызова проприетарного метода. В следующей таблице приведены различия между реализациями различных поставщиков SMS, которые я обнаружил.

 

JMS провайдер Реализация
Oracle AQ msg.setIntProperty («JMS_OracleDelay», задержка);
JBoss msg.setLongProperty («JMS_JBOSS_SCHEDULED_DELIVERY», сейчас + задержка);
ActiveMQ msg.setLongProperty (ScheduledMessage.AMQ_SCHEDULED_DELAY, задержка);
OpenJMS ((org.exolab.jms.message.MessageImpl) msg) .setJMSXRcvTimestamp (сейчас + задержка);
BEA Weblogic queueConnection = queueConnectionFactory.createQueueConnection (); QueueSession queueSession = queueConnection.createQueueSession (true, 0); QueueSender queueSender = queueSession.createSender (queue); ObjectMessage jmsMsg = queueSession.createObjectMessage (message); // Приводит queueSender к интерфейсу weblogic.jms.extensions.WLMessageProducer и устанавливает время доставки ((WLMessageProducer) queueSender) .setTimeToDeliver (timeToDeliver); queueSender.send (jmsMsg);

Есть ли у нас решение для провайдеров JMS, у которых нет встроенной поддержки отложенной доставки сообщений? Да. Я хотел бы предложить следующее решение.

Отправить сообщение в специальную очередь. Давайте назовем это DELAYED_QUEUE. Добавьте следующие специальные свойства в отложенное сообщение:

  • JMS_DESTINATION, которая содержит имя очереди или темы, в которую должно быть доставлено это сообщение.
  • DELIVERY_TIME, который содержит метку времени в миллисекундах (сейчас + задержка).

Для каждого отложенного сообщения с задержкой создайте запланированное задание, которое будет запускаться один раз, когда сообщение должно быть доставлено. Это запланированное задание создаст приемник JMS с селектором, который выглядит как DELIVERY_TIME <now (где now является отметкой времени), получает все сообщения с истекшим сроком действия и отправляет их в реальный пункт назначения JMS, используя свойство JMS_DESTINATION.


Запланированная задача может быть реализована как адаптер ресурсов (JCA):
BootstrapContext ctx;
ctx.getWorkManager().createTimer(). schedule(new DelayedMessageTimerTask(msg),
new Date(now + delay))

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

Выводы

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