Задержка повторной доставки сообщения JMS

У меня есть клиент JMS, который может подключаться по ssh к удаленным системам после получения сообщения (и делать там разные вещи - не имеет отношения к вопросу). Возможно, что за короткий период времени будут доставлены сотни таких сообщений, которые необходимо обработать как можно скорее.

Однако также возможно, что некоторые удаленные системы будут недоступны на момент получения сообщения, поэтому их следует отложить на более позднее время (например, на 1 час или около того). Лучшим решением было бы вернуть сообщение в очередь с некоторым заданным значением «задержки», которое укажет брокеру JMS не пытаться доставить сообщение снова в течение часа.

Что не нормально: спать в принимающей нити и просыпаться через час. Поскольку пул потребителей сообщений ограничен (например, доступно 8 подключений), наличие 8 недостижимых систем будет излишне блокировать всю обработку, что недопустимо.

Я не нашел настройки ни для сообщения, ни для самой очереди на такое значение "задержки", оно существует?

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


person egbokul    schedule 09.08.2010    source источник


Ответы (6)


Это невозможно через JMS API до JMS 2.0. Как правило, транспорты сообщений оптимизированы для максимально быстрой доставки сообщений и не имеют планировщиков, которые удерживали бы сообщение для повторной доставки через некоторый произвольный интервал. Предполагая, что существует поставщик транспорта, у которого есть такая функциональность, все, что вы пишете, будет затем привязано к этому поставщику транспорта, потому что, хотя код может быть JMS-совместимым, само приложение будет полагаться на это поведение, зависящее от поставщика.

См. Ответ @ Shashi для ответа, который относится к версиям MQ, поддерживающим JMS 2.0.

person T.Rob    schedule 09.08.2010
comment
Я полагаю, это было верно только для JMS 1.0? (См. Ответ Шаши) - person jpaugh; 18.07.2016
comment
Ага. Новые классы MQ JMS поддерживают отложенную доставку. - person T.Rob; 19.07.2016
comment
Этот ответ устарел, поскольку JMS 2.0 поддерживает отложенную доставку. Другой ответ следует принять. - person slykat; 19.08.2017
comment
Я согласен. Я бы посоветовал @egbokul отклонить мой, а затем принять ответ Шаши. Я думаю, мне нужно отредактировать его сначала IIRC, так что я сделаю это сейчас. - person T.Rob; 19.08.2017

Спецификация JMS 2.0 определяет «задержку доставки», при которой клиент может указать значение задержки доставки в миллисекундах для каждого отправляемого сообщения. Это значение определяет время доставки сообщения, которое является суммой задержки доставки сообщения и GMT, в которое оно отправлено (для транзакционных отправок это время отправки сообщения клиентом, а не время фиксации транзакции).

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

Эта функция очень удобна для описанного выше сценария.

person Shashi    schedule 25.04.2014

В этих ситуациях используются транзакции, управляемые контейнером. Транзакция запускается, когда метод 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>

А внутри bean-компонента, управляемого сообщениями, создается исключение RuntimeException, чтобы пометить его как сбойный, и сообщение будет возвращено в очередь.

Вот также свойства конфигурации для WebLogic Server: http://docs.oracle.com/cd/E12839_01/apirefs.1111/e13952/pagehelp/JMSjmstemplatesjmstemplateconfigredeliverytitle.html

person Amer A.    schedule 22.05.2013
comment
Также можно использовать файл sun-ejb.jar.xml. docs.oracle.com/cd/E19798-01/ 821-1750 / beaqm / index.html - person 99Sono; 22.08.2017

Я бы посмотрел на проблему так: пул потребителей сообщений jms доступен ... в то время как некоторые внутренние ресурсы (например, ssh) недоступны, чтобы разрешить завершение сообщения.

Если вы согласны с этим, тогда возникает проблема: почему пул потребителей доступен, если он не может завершить потребление? Если бы у вас был недоступен пул, сообщения бы накапливались в очереди ... пока они не стали доступными ... и это могло быть нормально, чтобы продолжить, когда они будут доступны. Затем, если это так, вам просто нужен компонент мониторинга для запуска / остановки пула в зависимости от наличия ресурсов. Вам не нужно ждать 1 час, но пока серверная часть недоступна. В конце концов, jms - это все, но не инструмент для мониторинга.

person user2701935    schedule 24.04.2014

По Glassfish можно использовать следующие ссылки.

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 в компоненте военного проекта.

person 99Sono    schedule 22.08.2017

Добрый день!

Именно для Oracle WebLogic Server есть два параметра:

  • Переопределение задержки повторной доставки - на уровне Очередь и
  • Задержка повторной доставки по умолчанию - на уровне Завод подключений.
person A. Neznakhin    schedule 04.04.2018