Фон
У меня есть очередь сообщений JMS на Apache Artemis 2.7.0.redhat-00056. Брокер настроен на redelivery-delay
из 10 минут. Если я опубликую сообщение в очереди, и оно не будет получено потребителем, то оно возвращается в очередь как запланированное сообщение, которое должно быть доставлено через 10 минут. Любые последующие сообщения, которые публикуются, обрабатываются сразу, поэтому очередь не блокируется запланированным сообщением.
Если несколько сообщений отправляются в быстрой последовательности, то происходит то, что все они терпят неудачу и планируются на 10 минут. В этом случае похоже, что Артемида пытается сохранить порядок сообщений.
Документация
Документы о повторной доставке говорят следующее:
Другие последующие сообщения будут доставляться регулярно, только задержанное сообщение будет отправлено обратно в очередь после задержки.
Документация по доставке
Проблема
Мне кажется непоследовательным, что если вы публикуете сообщения в тесной последовательности, кажется, что Артемида сохраняет порядок, тогда как если между сообщениями есть небольшая задержка, очередь не блокируется, и только неудачные сообщения планируются с задержкой (согласно документации).
Я пытаюсь найти решение, чтобы в случае сбоя одного сообщения и его повторной доставки в течение 10 минут оно не блокировало последующие сообщения.
Пример
Для этого не нужно ничего особенного. Как описано, вам просто нужно отправить несколько сообщений в быстрой последовательности в очередь с политикой повторной доставки в брокере. Я тестировал на следующем примере:
Приложение Spring, которое при запуске выдает пять сообщений.
@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 . Помимо присвоения ему имени, единственное, что было отмечено, это зависимость от Артемиды при обмене сообщениями.
<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>