Background
I have a JMS message queue on Apache Artemis 2.7.0.redhat-00056. The broker is configured with a redelivery-delay
of 10 minutes. If I publish a message to the queue and it fails on the consumer then it goes back to the queue as a scheduled message to be delivered in 10 minutes time. Any subsequent messages that are published are processed straightaway, so the queue is not blocked by the scheduled message.
If a number of messages are sent in quick succession then what happens is they all fail and get scheduled for 10 minutes time. In this case it looks like Artemis is trying to preserve the message order.
Documentation
The docs on redelivery say the following:
Other subsequent messages will be delivery regularly, only the cancelled message will be sent asynchronously back to the queue after the delay.
Problem
It seems inconsistent to me that if you publish the messages in close succession that Artemis appears to preserve the order, whereas if there is a slight delay between messages then the queue does not block and only the failed messages are scheduled with a delay (as per the docs).
I'm trying to find a solution so that if one message fails and needs to be redelivered in 10 minutes that it doesn't block subsequent messages.
Example
It doesn't need anything special to recreate this. As described you just need to send some messages in quick succession to a queue that has a redelivery policy on the broker. I've been testing with a basic example as follows:
Spring boot app that produces five messages on startup.
@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);
}
}
Consume messages and throw an error to trigger the redelivery policy.
@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");
}
}
The app was generated using the spring boot initializr. Other than giving it a name, the only thing of note selected was the artemis dependancy under messaging.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-artemis</artifactId>
</dependency>
In application.properties I have configured the connection properties to the locally running instance of Artemis.
spring.artemis.mode=native
spring.artemis.host=localhost
spring.artemis.port=61616
spring.artemis.user=
spring.artemis.password=
And on the broker I have configured the queue with a redelivery policy. Note: I set the delay to 0 here and the problem still occurs in that all messages are blocked until the first message has had three attempts and been moved to the DLQ. If you change the delay to a positive number then you see all five messages are scheduled for delivery later.
<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>