Задержка повторной доставки сообщения JMS
У меня есть JMS-клиент, который может получить ssh для удаленных систем при получении сообщения (и делать там разные вещи - не относящиеся к вопросу). Возможно, что за короткое время появятся сотни таких сообщений, которые необходимо обработать как можно скорее.
Однако также возможно, что некоторые удаленные системы будут недоступны при получении сообщения, поэтому их следует отложить на более позднее время (например, 1 час или около того). Лучшим решением было бы поместить сообщение обратно в очередь с некоторым набором значений "задержки", которые сообщат JMS-брокеру не пытаться доставить сообщение снова в течение часа.
Что не в порядке: спи в принимающей ветке и проснись через час. Поскольку пул потребителя сообщений ограничен (например, доступно 8 соединений), имеющее 8 недостижимых систем, излишне заблокирует всю обработку, что недопустимо.
Я не нашел настройки ни для сообщения, ни для самой очереди для такого значения "задержки", оно существует?
Обходное решение - использовать вторую очередь для хранения сообщений в недоступных системах и обрабатывать их отдельно. Но это не очень элегантное решение и требует дополнительного программирования. Возможно, есть лучший способ.
6 ответов
Это невозможно через JMS API до JMS 2.0. Как правило, транспорты сообщений оптимизированы для максимально быстрой доставки сообщений и не имеют планировщиков для хранения сообщений для повторной доставки через некоторый произвольный интервал. Предполагая, что есть транспортный провайдер, обладающий такой функциональностью, все, что вы пишете, будет связано с этим транспортным провайдером, потому что, хотя код может быть JMS-совместимым, само приложение будет полагаться на это поведение, специфичное для поставщика.
Смотрите ответ @Shashi для ответа, который относится к версиям MQ, которые поддерживают JMS 2.0.
Спецификация JMS 2.0 определяет "задержку доставки", когда клиент может указать значение задержки доставки в миллисекундах для каждого отправляемого сообщения. Это значение определяет время доставки сообщения, которое является суммой задержки доставки сообщения и GMT, когда оно было отправлено (для транзакционных отправок это время, когда клиент отправляет сообщение, а не время совершения транзакции).
Время доставки сообщения - это самое раннее время, когда провайдер JMS может сделать сообщение видимым в целевом месте назначения и доступным для доставки потребителям. Поставщик не должен доставлять сообщения до истечения времени доставки.
Эта функция очень удобна для сценария, описанного выше.
В этих ситуациях используются управляемые контейнером транзакции. Транзакция начинается, когда onMessage
метод вызывается контейнером и фиксируется, если onMessage
метод завершается успешно (он потерпит неудачу, когда выбрасывается RuntimeException или setRollBackOnly
вызывается из контекста MessageDrivenBean). Вы также можете настроить интервал повторной доставки и максимальное количество повторных доставок.
Если вы используете OpenMQ с сервером Glassfish, вы можете настроить это внутри дескриптора ejb-jar.xml. Внутри дескриптора ejb-jar.xml задайте свойства endpointExceptionRedeliveryInterval (в миллисекундах) и endpointExceptionRedeliveryAttempts (число раз, когда сообщение доставляется до его отправки в очередь мертвых сообщений). Вот пример:
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
version="3.1">
<enterprise-beans>
<message-driven>
<ejb-name>EjbName</ejb-name>
<ejb-class>com.example.MyMessageDrivenBean</ejb-class>
<messaging-type>javax.jms.MessageListener</messaging-type>
<transaction-type>Container</transaction-type>
<activation-config>
<activation-config-property>
<activation-config-property-name>destination</activation-config-property-name>
<activation-config-property-value>someQueue</activation-config-property-value>
</activation-config-property>
<activation-config-property>
<activation-config-property-name>destinationType</activation-config-property-name>
<activation-config-property-value>javax.jms.Queue</activation-config-property-value>
</activation-config-property>
<activation-config-property>
<activation-config-property-name>endpointExceptionRedeliveryInterval</activation-config-property-name>
<activation-config-property-value>5000</activation-config-property-value>
</activation-config-property>
<activation-config-property>
<activation-config-property-name>endpointExceptionRedeliveryAttempts</activation-config-property-name>
<activation-config-property-value>4</activation-config-property-value>
</activation-config-property>
</activation-config>
</message-driven>
</enterprise-beans>
</ejb-jar>
А внутри компонента, управляемого сообщениями, выдается исключение RuntimeException, чтобы пометить его как сбойное, и сообщение будет возвращено в очередь.
Вот также свойства конфигурации для сервера WebLogic: http://docs.oracle.com/cd/E12839_01/apirefs.1111/e13952/pagehelp/JMSjmstemplatesjmstemplateconfigredeliverytitle.html
Я бы посмотрел на проблему следующим образом: доступен пул потребителя сообщений jms... в то время как некоторые внутренние ресурсы (т. Е. Ssh) не доступны для завершения сообщения.
Если вы согласны с этим, тогда возникает проблема: почему доступен пул потребителей, поскольку он не может завершить потребление? Если бы у вас не было пула, то сообщения могли бы накапливаться в очереди... до тех пор, пока они не стали доступны... и было бы неплохо продолжить, когда они будут доступны. Тогда, если это так, вам просто нужен компонент мониторинга для запуска / остановки пула в зависимости от наличия ресурсов. Вам не нужно ждать 1 час, но пока бэкэнд не доступен. в конце концов, jms - это все, но не инструмент мониторинга.
Добрый день!
Для Oracle WebLogic Server точно есть два параметра:
- Redelivery Delay Override - на уровне очереди, и
- Задержка возврата по умолчанию - на уровне фабрики соединений.
На стеклянной рыбе можно использовать следующие ссылки.
https://docs.oracle.com/cd/E19798-01/821-1794/aeooq/index.html
По приведенной выше ссылке вы получите список свойств активации, которые поддерживаются Glassfish. Например, endpointExceptionRedeliveryAttempts -
Количество повторных доставок сообщения, когда MDB генерирует исключение во время доставки сообщения
Затем у вас есть следующая ссылка, которая описывает допустимые элементы xml для использования в файле sun-ejb-jar.xml, который поддерживается glassfish. https://docs.oracle.com/cd/E19798-01/821-1750/beaqm/index.html
Наконец, вы можете настроить Mdb, как показано в следующем фрагменте.
<ejb>
<ejb-name>MyMdbWith0MsRedeliveryDelayAndMultipleRedeliveriesMdb</ejb-name>
<bean-pool>
<steady-pool-size>1</steady-pool-size>
<resize-quantity>1</resize-quantity>
<max-pool-size>1</max-pool-size>
</bean-pool>
<mdb-resource-adapter>
<activation-config>
<activation-config-property>
<activation-config-property-name>endpointExceptionRedeliveryAttempts</activation-config-property-name>
<activation-config-property-value>1000</activation-config-property-value>
</activation-config-property>
<activation-config-property>
<activation-config-property-name>endpointExceptionRedeliveryAttempts</activation-config-property-name>
<activation-config-property-value>0</activation-config-property-value>
</activation-config-property>
</activation-config>
</mdb-resource-adapter>
</ejb>
Это должно гарантировать, что для этого конкретного mdb glassfish немедленно доставит сообщение, а в случае неудачи немедленно предпримет повторную попытку.
В вашем WAR-проекте создайте sub-ejb-jar.xml и поместите его в WEB-INF/sun-ejb-jar.xml.
Если вы используете maven, это будет ваш путь src/main/webapp/WEB-INF/sub-ejb-jar.xml в компоненте проекта войны.