背景
我在Apache Artemis 2.7.0.redhat-00056上有一个JMS消息队列。代理配置为10分钟的redelivery-delay
。如果我将消息发布到队列,但在使用方上失败,则它将作为调度消息返回队列,以在10分钟内传递。任何后续发布的消息都会被立即处理,因此队列不会被计划的消息阻塞。
如果连续快速发送大量消息,那么将发生所有消息失败并安排10分钟的时间。在这种情况下,Artemis似乎试图保留消息顺序。
文档
有关重新交付的文档说:
其他后续消息将定期发送,只有取消的消息将在延迟后异步发送回队列。
问题
对于我来说似乎不一致,如果您连续连续地发布消息,那么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>
答案 0 :(得分:0)
我得出的结论是,这是Artemis的一个错误。我为此举了票,并留下了遇到同样问题的其他人的评论。
https://issues.apache.org/jira/browse/ARTEMIS-2417
同时,我不得不更改客户端应用程序以处理重新交付策略本身。如果在读取消息时出错,那么我们将在消息上增加一个计数器,并将其写为具有所需延迟的新消息。然后,确认正在消耗的消息以解除阻塞队列并允许读取其他消息。我保留了在代理程序上配置的重新交付策略,以作为回退,以防万一出现此逻辑之外的错误或未捕获到的错误。这不是很理想,但至少现在满足了要求。