当Spring JMS 发生异常时停止在队列的消费者中一次又一次地接收消息
Stop receiving again and again messages in consumer of the queue when an exception occurs in Spring JMS
我从发件人应用程序发送消息如下。
@GetMapping("send/event")
public void sendEvent() {
try {
String stringEvent = objectMapper.writeValueAsString(getEvent());
jmsTemplate.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
jmsTemplate.setSessionTransacted(false);
jmsTemplate.convertAndSend(SEND_QUEUE_NAME, stringEvent);
} catch (JmsException | JsonProcessingException e) {
e.printStackTrace();
}
}
并且在接收方应用程序中,我收到如下消息。
@Override
@JmsListener(destination = "${mq.receive_queue}")
public void receive(Message message) {
try {
String jsonEvent = ((TextMessage) message).getText();
Event event = objectMapper.readValue(jsonEvent, Event.class);
System.out.println(event.toString());
message.acknowledge();
validateEventRequest(event);
} catch (JMSException | IOException e) {
e.printStackTrace();
}
}
主要问题是 validateEventRequest(event);
调用时。因为在这个方法中,我有几个服务和场景可能会引发异常。我不希望抛出异常时,消息回滚到队列并再次接收。我只想在发生异常时完全消费消息。
因此,我将这些行添加到发件人应用程序中。
jmsTemplate.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
jmsTemplate.setSessionTransacted(false);
但没有任何变化。如果有人对此有想法,我将不胜感激。
附加信息
我在接收器应用程序的接收方法中调用了这些
int deliveryMode = jmsTemplate.getDeliveryMode(); -->2
int sessionAcknowledgeMode = jmsTemplate.getSessionAcknowledgeMode(); -->1
int jmsDeliveryMode = message.getJMSDeliveryMode(); -->2
boolean jmsRedelivered = message.getJMSRedelivered(); -->true
很可能您的 validateEventRequest(event)
抛出了 JMSException
或 IOException
(或其子类之一)以外的东西,这意味着 [=15] 中的 catch
=] 将 而不是 实际捕获它。我相信当此异常从您的 receive
方法中抛出时,将触发消息的重新传递。我建议您改用更通用的 Exception
,例如:
@Override
@JmsListener(destination = "${mq.receive_queue}")
public void receive(Message message) {
try {
String jsonEvent = ((TextMessage) message).getText();
Event event = objectMapper.readValue(jsonEvent, Event.class);
System.out.println(event.toString());
message.acknowledge();
validateEventRequest(event);
} catch (Exception e) {
e.printStackTrace();
}
}
此外,值得注意的是,更改消息的发送方式不会影响消息的接收方式。如果您想更改消息的接收方式,则需要更改接收方应用程序。
我从发件人应用程序发送消息如下。
@GetMapping("send/event")
public void sendEvent() {
try {
String stringEvent = objectMapper.writeValueAsString(getEvent());
jmsTemplate.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
jmsTemplate.setSessionTransacted(false);
jmsTemplate.convertAndSend(SEND_QUEUE_NAME, stringEvent);
} catch (JmsException | JsonProcessingException e) {
e.printStackTrace();
}
}
并且在接收方应用程序中,我收到如下消息。
@Override
@JmsListener(destination = "${mq.receive_queue}")
public void receive(Message message) {
try {
String jsonEvent = ((TextMessage) message).getText();
Event event = objectMapper.readValue(jsonEvent, Event.class);
System.out.println(event.toString());
message.acknowledge();
validateEventRequest(event);
} catch (JMSException | IOException e) {
e.printStackTrace();
}
}
主要问题是 validateEventRequest(event);
调用时。因为在这个方法中,我有几个服务和场景可能会引发异常。我不希望抛出异常时,消息回滚到队列并再次接收。我只想在发生异常时完全消费消息。
因此,我将这些行添加到发件人应用程序中。
jmsTemplate.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
jmsTemplate.setSessionTransacted(false);
但没有任何变化。如果有人对此有想法,我将不胜感激。
附加信息
我在接收器应用程序的接收方法中调用了这些
int deliveryMode = jmsTemplate.getDeliveryMode(); -->2
int sessionAcknowledgeMode = jmsTemplate.getSessionAcknowledgeMode(); -->1
int jmsDeliveryMode = message.getJMSDeliveryMode(); -->2
boolean jmsRedelivered = message.getJMSRedelivered(); -->true
很可能您的 validateEventRequest(event)
抛出了 JMSException
或 IOException
(或其子类之一)以外的东西,这意味着 [=15] 中的 catch
=] 将 而不是 实际捕获它。我相信当此异常从您的 receive
方法中抛出时,将触发消息的重新传递。我建议您改用更通用的 Exception
,例如:
@Override
@JmsListener(destination = "${mq.receive_queue}")
public void receive(Message message) {
try {
String jsonEvent = ((TextMessage) message).getText();
Event event = objectMapper.readValue(jsonEvent, Event.class);
System.out.println(event.toString());
message.acknowledge();
validateEventRequest(event);
} catch (Exception e) {
e.printStackTrace();
}
}
此外,值得注意的是,更改消息的发送方式不会影响消息的接收方式。如果您想更改消息的接收方式,则需要更改接收方应用程序。