Spring boot ActiveMQ重新交付不起作用
我正在尝试使用ActiveMQ实现死信队列。不幸的是,这方面的文档在某些方面相当模糊,我似乎无法正确设置所有内容 我配置了以下bean:Spring boot ActiveMQ重新交付不起作用,spring-boot,activemq,dead-letter,Spring Boot,Activemq,Dead Letter,我正在尝试使用ActiveMQ实现死信队列。不幸的是,这方面的文档在某些方面相当模糊,我似乎无法正确设置所有内容 我配置了以下bean: @Bean public JmsTemplate createJMSTemplate() { logger.info("createJMSTemplate"); JmsTemplate jmsTemplate = new JmsTemplate(getActiveMQConnectionFactory()); jmsTemplate.s
@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设置。我错过了什么 因为您正在使用
this.session=connection.createSession(false,session.CLIENT\u确认)代码>
调用message.acknowledge()
与调用session.acknowledge()相同代码>
要使ActiveMQ重新交付成功地与您的配置一起工作,有一些可能只需进行最小的更改:
调用QueueReceiver.this.session.recover()代码>
代替调用QueueReceiver.this.session.rollback()代码>
void org.apache.activemq.ActiveMQSession.recover()引发JMSException
停止此会话中的邮件传递,并重新启动邮件传递
使用最早的未确认消息
所有消费者都以串行顺序传递消息。承认
接收到的消息会自动确认已发送的所有消息
已交付给客户
重新启动会话会导致会话执行以下操作:•停止
邮件传递•标记所有可能已传递的邮件
但未确认为“重新交付”•重新启动交付顺序
包括以前收到的所有未确认的邮件
交付。重新传递的消息不必以精确的方式传递
他们的原始交货单
使用
this.session=connection.createSession(false,org.apache.activemq.ActiveMQSession.INDIVIDUAL_ACKNOWLEDGE)代码>
打电话
((org.apache.activemq.command.ActiveMQMessage)消息)
,请注意,不调用此方法就像回滚一样,意味着消息未被确认,并且在onMessage
方法中引发异常将调用QueueReceiver.this.consumer.rollback()
只需调用QueueReceiver.this.consumer.rollback()代码>org.apache.activemq.ActiveMQMessageConsumer.rollback()代替调用QueueReceiver.this.session.rollback()代码>
因此,事实证明这是一系列问题的结合:
- 会话确认模式需要设置为
ActiveMQSession.INDIVIDUAL_acknowledge
- 我使用的是
session.recover()
而不是rollback()
- ActiveMQ代理未正确配置。我需要将此位添加到activemq.xml配置文件中(将其放在
标记下)
- 确保您没有激活任何可能会干扰ActiveMQConnectionFactory配置的
redeliveryPlugin
我似乎在使用ActiveMQSession.INDIVIDUAL\u ACKNOWLEDGE
和this.session.rollback()创建会话方面取得了一些成功。消息仅在应用程序停止时添加到DLQ,但它似乎会无限次重试消息,而不是我配置的3次重新传递。
<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>