ActiveMQの高度な機能を備えたデッドレターキュー

 

DLQ-Dead Letter Queueは、失敗したメッセージまたは期限切れのメッセージを保存するために使用されます。

メッセージは、次の状況で再配信されます

  • トランザクションセッションが使用され、rollback()が呼び出されます(トランザクションセッションが使用され、rollback()メソッドが呼び出されます)。
  • トランザクションセッションは、コミットが呼び出される前に閉じられます(トランザクションセッション、コミットは閉じる前に呼び出されます)。
  • セッションはCLIENT_ACKNOWLEDGEを使用しており、Session.recover()が呼び出されます(セッションでCLIENT_ACKNOWLEDGE署名モードを使用し、Session.recover()メソッドを呼び出します)。 
  • セッションでAUTO_ACKNOWLEDGE署名モードを使用します。非同期(messageListener)を消費するメッセージの場合、onMessageメソッドが異常であり、キャッチされない場合、メッセージは再配信されます。
     

メッセージがmaximumRedeliveriesを超えて再配信されると(デフォルトは6回です。具体的な設定については、次のコンテンツを参照してください)、「Poison ack」がブローカーに送信されます。このメッセージは、ポイズンピルと見なされます。ブローカーは、後続の処理のためにこのメッセージをDLQに送信します。

ActiveMQ管理ターミナルにログインすると、ActiveMqにデフォルトのデッドレターチームActiveMQ.DLQがあることがわかります。設定されていない場合、失敗したメッセージは自動的にこのキューに入ります。デフォルトの永続メッセージは期限切れになり、DLQに送信され、非永続メッセージはDLQに送信されません。この記事では、Springでプライベートメッセージの再送信メカニズムを導入する方法を紹介します。
 

デフォルト:永続メッセージは期限切れになり、DLQに送信されます。非永続メッセージは、DLQに送信されません(再配信なし)。

カスタムredeliveryPolicyをconnectionFactoryに挿入して、デフォルトのパラメーターを変更できます。

    <bean id="redeliveryPolicy" class="org.apache.activemq.RedeliveryPolicy">
        <!--是否在每次尝试重新发送失败后,增长这个等待时间-->
        <property name="useExponentialBackOff" value="true"></property>
        <!--重发次数,默认为6次-->
        <property name="maximumRedeliveries" value="5"></property>
        <!--重发时间间隔,默认为1秒-->
        <property name="initialRedeliveryDelay" value="1000"></property>
        <!--第一次失败后重新发送之前等待500毫秒,第二次失败再等待500 * 2毫秒,这里的2就是value-->
        <property name="backOffMultiplier" value="2"></property>
        <!--最大传送延迟,只在useExponentialBackOff为true时有效,当重连间隔大于最大重连间隔时,以后每次重连间隔都为最大重连间隔。-->
        <property name="maximumRedeliveryDelay" value="1000"></property>
    </bean>


    <!-- 在ConnectionFactory中应用这个Policy。 -->

    <bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL" value="tcp://188.166.236.173:61616"/>         
        <property name="redeliveryPolicy" ref="activeMQRedeliveryPolicy"/>
        <!-- <property name="useAsyncSend" value="true"/> 默认就是异步发送-->
    </bean>     

 

ActiveMQサーバーのconf / activemq.xmlzhongのブローカーノードの下に追加します。

    <destinationPolicy>
        <policyMap>
          <policyEntries>
              <policyEntry queue=">">
                 <deadLetterStrategy>
                    <individualDeadLetterStrategy queuePrefix="DLQ." useQueueForQueueMessages="true" />
                    <!-- 如果不想将过期消息放到DLQ中
                    <sharedDeadLetterStrategy processExpired="false" />  
                    -->
                    <!-- 如果想将非持久消息放入DLQ
                    <sharedDeadLetterStrategy processNonPersistent="true" />
                    -->
                 </deadLetterStrategy>
              </policyEntry>

              <policyEntry topic=">" >
                <pendingMessageLimitStrategy>
                   <constantPendingMessageLimitStrategy limit="1000"/>
                </pendingMessageLimitStrategy>
              </policyEntry>
          </policyEntries>
        </policyMap>
    </destinationPolicy>

再配信をテストするには、次の4つの方法があります。

トランザクションセッションで、session.rollback()を呼び出します。

    <bean id="jmsQueueContainerForDLQ" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory" />
        <property name="destination" ref="queueDestination" />
        <property name="messageListener" ref="consumerMessageListenerDLQ" />
        <!-- 如果支持事物的话,在接收消息后rollback会重发消息,进入死信队列,默认为false -->
        <property name="sessionTransacted" value="true" />
    </bean>

    public class ConsumerMessageListenerDLQ implements SessionAwareMessageListener<TextMessage> {
        public void onMessage(TextMessage message, Session session) {
            if(message instanceof TextMessage) {
                TextMessage textMessage = (TextMessage) message;
                try {
                        String text = textMessage.getText();
                        System.out.println(String.format("Received: %s",text));
                        if ("i want to redelivery".equals(text)){
                            throw new JMSException("process failed to test redelivery and DLQ");
                    }

                } catch (JMSException e) {
                    System.out.println("there is JMS exception: " + e.getMessage() );
                    //throw JmsUtils.convertJmsAccessException(e);
                    try {
                        session.rollback();
                    } catch (JMSException e1) {
                        e1.printStackTrace();
                    }
                }
            }
        }
    }

トランザクションセッションでは、commit.close()がsession.commit()の前に呼び出されます。

    <bean id="jmsQueueContainerForDLQ" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory" />
        <property name="destination" ref="queueDestination" />
        <property name="messageListener" ref="consumerMessageListenerDLQ" />
        <!-- 如果支持事物的话,在接收消息后rollback会重发消息,进入死信队列,默认为false -->
        <property name="sessionTransacted" value="true" />
    </bean>

    public class ConsumerMessageListenerDLQ implements SessionAwareMessageListener<TextMessage> {
        public void onMessage(TextMessage message, Session session) {
            if(message instanceof TextMessage) {
                TextMessage textMessage = (TextMessage) message;
                try {
                        String text = textMessage.getText();
                        System.out.println(String.format("Received: %s",text));
                        if ("i want to redelivery".equals(text)){
                            throw new JMSException("process failed to test redelivery and DLQ");
                    }

                } catch (JMSException e) {
                    System.out.println("there is JMS exception: " + e.getMessage() );
                    //throw JmsUtils.convertJmsAccessException(e);
                    try {
                        session.close();
                    } catch (JMSException e1) {
                        e1.printStackTrace();
                    }
                }
            }
        }
    }

CLIENT_ACKNOWLEDGE署名モードがセッションで使用され、session.recover()が呼び出されます。

    <bean id="jmsQueueContainerForDLQ" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="connectionFactory" />
        <property name="destination" ref="queueDestination" />
        <property name="messageListener" ref="consumerMessageListenerDLQ" />
        <!-- 自动应答模式消息不会重发,进入死信队列 -->
        <property name="sessionAcknowledgeMode" value="2"/>
    </bean>

    public class ConsumerMessageListenerDLQ implements SessionAwareMessageListener<TextMessage> {
        public void onMessage(TextMessage message, Session session) {
            if(message instanceof TextMessage) {
                TextMessage textMessage = (TextMessage) message;
                try {
                        String text = textMessage.getText();
                        System.out.println(String.format("Received: %s",text));
                        if ("i want to redelivery".equals(text)){
                            throw new JMSException("process failed to test redelivery and DLQ");
                    }

                } catch (JMSException e) {
                    System.out.println("there is JMS exception: " + e.getMessage() );
                    //throw JmsUtils.convertJmsAccessException(e);
                    try {
                        session.recover();
                    } catch (JMSException e1) {
                        e1.printStackTrace();
                    }
                }
            }
        }
    }

セッションでAUTO_ACKNOWLEDGE署名モードを使用すると、非同期リスナーのonMessage()例外がキャッチされませんでした。

    public class Listener implements MessageListener {
        public void onMessage(Message message) {
            int i = 8/0;//会导致redelivery
            try {
                if(message instanceof ActiveMQTextMessage){
                    ActiveMQTextMessage textMessage = (ActiveMQTextMessage) message;
                    System.out.println("收到的消息:" + textMessage.getText());                   }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

永続メッセージの有効期限が切れると、DLQに送信されます。

    <!-- 定义JmsTemplate的Queue类型 -->
    <bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate">
        <!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 -->
        <constructor-arg ref="connectionFactory" />
        <property name="messageConverter" ref="messageConverter"></property>
        <!-- 非pub/sub模型(发布/订阅),即队列模式 -->
        <property name="pubSubDomain" value="false" />
        <!-- 发送模式  DeliveryMode.NON_PERSISTENT=1:非持久 ; DeliveryMode.PERSISTENT=2:持久-->
        <property name="deliveryMode" value="2" />
        <!-- 2秒后过期,这个对点对点模式有效 -->
        <property name="timeToLive" value="2000" />
    </bean>

 

おすすめ

転載: blog.csdn.net/m0_46405589/article/details/115183914