如何设置ActiveMQ Artemis重新交付策略不阻止队列

时间:2019-07-04 10:23:01

标签: jms spring-jms activemq-artemis

背景

我在Apache Artemis 2.7.0.redhat-00056上有一个JMS消息队列。代理配置为10分钟的redelivery-delay。如果我将消息发布到队列,但在使用方上失败,则它将作为调度消息返回队列,以在10分钟内传递。任何后续发布的消息都会被立即处理,因此队列不会被计划的消息阻塞。

如果连续快速发送大量消息,那么将发生所有消息失败并安排10分钟的时间。在这种情况下,Artemis似乎试图保留消息顺序。

文档

有关重新交付的文档说:

  

其他后续消息将定期发送,只有取消的消息将在延迟后异步发送回队列。

Redelivery documentation

问题

对于我来说似乎不一致,如果您连续连续地发布消息,那么Artemis似乎会保留订单,而如果消息之间的延迟很小,则队列不会阻塞,只有失败的消息会被延迟调度(根据文档)。

我正在尝试找到一种解决方案,以便如果一条消息失败并且需要在10分钟内重新发送,则它不会阻止后续消息。

示例

不需要任何特殊的操作来重新创建它。如前所述,您只需要快速将一些消息发送到在代理上具有重新交付策略的队列。我一直在用以下基本示例进行测试:

Spring boot应用程序在启动时会产生五条消息。

@SpringBootApplication
public class ArtemisTestApplication
{

    private Logger logger = LoggerFactory.getLogger(ArtemisTestApplication.class);

    @Autowired
    private JmsTemplate jmsTemplate;

    @PostConstruct
    public void init()
    {
        send("Message1");
        send("Message2");
        send("Message3");
        send("Message4");
        send("Message5");
    }

    public void send(String msg)
    {
        logger.debug("Sending message :{}", msg);
        jmsTemplate.convertAndSend("jms.queue.TestQueue", msg);
    }

    public static void main(String[] args)
    {
        SpringApplication.run(ArtemisTestApplication.class, args);
    }

}

使用消息并引发错误以触发重新交付策略。

@Component
public class TestConsumer
{
    private Logger logger = LoggerFactory.getLogger(TestConsumer.class);

    @JmsListener(destination = "jms.queue.TestQueue")
    public void receive(TextMessage message) throws JMSException
    {
        logger.debug("Message received: {}", message.getText());
        throw new RuntimeException("Force redelivery policy");
    }
}

该应用是使用spring boot initializr生成的。除了给它起个名字外,唯一要注意的是在消息传递下对阿耳emi弥斯的依赖。

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-artemis</artifactId>
    </dependency>

在application.properties中,我已配置了到本地运行的Artemis实例的连接属性。

spring.artemis.mode=native
spring.artemis.host=localhost
spring.artemis.port=61616
spring.artemis.user=
spring.artemis.password=

然后在代理上,我用重新交付策略配置了队列。注意:我在这里将延迟设置为0,问题仍然存在,因为所有消息都被阻塞,直到第一个消息进行了三次尝试并被移至DLQ。如果您将延迟更改为正数,那么您会看到所有五封邮件都计划在以后发送。

<address-settings>      
    <address-setting match="jms.queue.TestQueue">            
        <dead-letter-address>DLQ</dead-letter-address>                      
        <redelivery-delay>0</redelivery-delay>    
        <max-delivery-attempts>3</max-delivery-attempts>
    </address-setting>    
  </address-settings>

<addresses>     
    <address name="DLQ">            
        <anycast>               
          <queue name="DLQ" />            
        </anycast>         
      </address>       
      <address name="jms.queue.TestQueue">            
        <anycast>               
          <queue name="jms.queue.TestQueue" />            
        </anycast>         
      </address>                      
</addresses>

1 个答案:

答案 0 :(得分:0)

我得出的结论是,这是Artemis的一个错误。我为此举了票,并留下了遇到同样问题的其他人的评论。

https://issues.apache.org/jira/browse/ARTEMIS-2417

同时,我不得不更改客户端应用程序以处理重新交付策略本身。如果在读取消息时出错,那么我们将在消息上增加一个计数器,并将其写为具有所需延迟的新消息。然后,确认正在消耗的消息以解除阻塞队列并允许读取其他消息。我保留了在代理程序上配置的重新交付策略,以作为回退,以防万一出现此逻辑之外的错误或未捕获到的错误。这不是很理想,但至少现在满足了要求。