ActiveMQ重新传递不起作用

时间:2016-12-16 10:43:35

标签: spring-boot activemq dead-letter

我正在使用ActiveMQ尝试使用死信队列。不幸的是,这方面的文档在某些方面相当模糊,我似乎无法正确设置所有内容。

我配置了以下Beans:

@Bean
public JmsTemplate createJMSTemplate() {
    logger.info("createJMSTemplate");
    JmsTemplate jmsTemplate = new JmsTemplate(getActiveMQConnectionFactory());
    jmsTemplate.setDefaultDestinationName(queue);
    jmsTemplate.setDeliveryPersistent(true);
    jmsTemplate.setDeliveryMode(DeliveryMode.PERSISTENT);
    return jmsTemplate;
}

@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    factory.setConnectionFactory(getActiveMQConnectionFactory());
    factory.setConcurrency("1-10");
    factory.setSessionTransacted(false);
    factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
    return factory;
}

@Bean
public ConnectionFactory getActiveMQConnectionFactory() {
    // Configure the ActiveMQConnectionFactory
    ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory();
    activeMQConnectionFactory.setBrokerURL("tcp://127.0.0.1:61616");
    activeMQConnectionFactory.setTrustedPackages(Arrays.asList("com.company"));

    // Configure the redeliver policy and the dead letter queue
    RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy();
    redeliveryPolicy.setInitialRedeliveryDelay(0);
    redeliveryPolicy.setRedeliveryDelay(10000);
    redeliveryPolicy.setUseExponentialBackOff(true);
    redeliveryPolicy.setMaximumRedeliveries(3);
    RedeliveryPolicyMap redeliveryPolicyMap = activeMQConnectionFactory.getRedeliveryPolicyMap();
    redeliveryPolicyMap.put(new ActiveMQQueue(queue), redeliveryPolicy);
    activeMQConnectionFactory.setRedeliveryPolicy(redeliveryPolicy);

    return activeMQConnectionFactory;
}

这是我的接收代码:

@Autowired
private ConnectionFactory connectionFactory;

private static Logger logger = LoggerFactory.getLogger(QueueReceiver.class);
private Connection connection;
private Session session;
private SegmentReceiver callback;

@PostConstruct
private void init() throws JMSException, InterruptedException {
    logger.info("Initializing QueueReceiver...");
    this.connection = connectionFactory.createConnection();
    this.session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
    Queue q = session.createQueue(queue);
    logger.info("Creating consumer for queue '{}'", q.getQueueName());
    MessageConsumer consumer = session.createConsumer(q);
    this.callback = new SegmentReceiver();
    consumer.setMessageListener(callback);
    this.connection.start();
}

@PreDestroy
private void destroy() throws JMSException {
    logger.info("Destroying QueueReceiver...");
    this.session.close();
    this.connection.close();
}

private class SegmentReceiver implements MessageListener {

    @Override
    public void onMessage(Message message) {
        logger.info("onMessage");
        try {
            TextMessage textMessage = (TextMessage) message;
            Segment segment = Segment.fromJSON(textMessage.getText());
            if (segment.shouldFail()) {
                throw new IOException("This segment is expected to fail");
            }
            System.out.println(segment.getText());
            message.acknowledge();
        }
        catch(IOException | JMSException exception) {
            logger.error(exception.toString());
            try {
                QueueReceiver.this.session.rollback();
            } catch (JMSException e) {
                logger.error(e.toString());
            }
            throw new RuntimeException(exception);
        }
    }

}

然而,没有任何反应。我使用默认配置使用开箱即用的Apache ActiveMQ 5.14.2设置。我在这里错过了什么?

2 个答案:

答案 0 :(得分:2)

因为你正在使用 this.session = connection.createSession(false,Session.CLIENT_ACKNOWLEDGE);
调用message.acknowledge();与调用session.acknowledge();相同。

让ActiveMQ重新传递成功地使用您的配置,有一些可能性,只需极少的更改:

  1. 致电QueueReceiver.this.session.recover();
    代替致电QueueReceiver.this.session.rollback();
  2.   

    void org.apache.activemq.ActiveMQSession.recover()抛出JMSException

         

    在此会话中停止邮件传递,并重新启动邮件传递   用最古老的未经确认的消息。

         

    所有消费者都按顺序发送消息。承认一个   收到的消息会自动确认所有消息   已交付给客户。

         

    重新启动会话会使其执行以下操作:•停止   邮件传递•标记可能已传递的所有邮件   但未被承认为" redelivered" •重新启动交货顺序   包括之前所有未经确认的消息   交付。重新传递的消息不必完全传递   他们原来的交货单。

    1. 使用 this.session = connection.createSession(false, org.apache.activemq.ActiveMQSession.INDIVIDUAL_ACKNOWLEDGE); 并打电话 ((org.apache.activemq.command.ActiveMQMessage) message ).acknowledge();,请注意,不调用此方法就像回滚一样,意味着邮件未得到确认,并且在onMessage方法中抛出异常将调用 org.apache.activemq的QueueReceiver.this.consumer.rollback(); .ActiveMQMessageConsumer.rollback()

    2. 只需调用QueueReceiver.this.consumer.rollback(); org.apache.activemq.ActiveMQMessageConsumer.rollback()代替调用QueueReceiver.this.session.rollback();

答案 1 :(得分:0)

所以它被证明是一系列问题:

  • 会话确认模式需要设置为ActiveMQSession.INDIVIDUAL_ACKNOWLEDGE
  • 我正在使用session.recover()而不是rollback()
  • 未正确配置ActiveMQ代理。我需要将此位添加到activemq.xml配置文件中(将其放在<broker>标记下)。

        <destinationPolicy>
        <policyMap>
          <policyEntries>
            <policyEntry topic=">" >
                <!-- The constantPendingMessageLimitStrategy is used to prevent
                     slow topic consumers to block producers and affect other consumers
                     by limiting the number of messages that are retained
                     For more information, see:
    
                     http://activemq.apache.org/slow-consumer-handling.html
    
                -->
              <pendingMessageLimitStrategy> 
                <constantPendingMessageLimitStrategy limit="1000"/>
              </pendingMessageLimitStrategy>
            </policyEntry>
            <!-- Set the following policy on all queues using the '>' wildcard -->
            <policyEntry queue=">">
                <deadLetterStrategy>
                    <!--
                      Use the prefix 'DLQ.' for the destination name, and make
                      the DLQ a queue rather than a topic
                    -->
                    <individualDeadLetterStrategy queuePrefix="DLQ." useQueueForQueueMessages="true"/>
                </deadLetterStrategy>
            </policyEntry>
          </policyEntries>
        </policyMap>
    </destinationPolicy>
    
  • 确保您没有激活任何可能导致ActiveMQConnectionFactory配置混乱的redeliveryPlugin