Spring JMS监听器即使出现异常也会确认接收

9

我正在使用JMS将消息发送/接收到我的SQS队列,但是即使使用了client_acknowledge,当出现异常时仍然无法重新传递消息。如何实现这一点? 我尝试了一个简单的测试:

@JmsListener(destination = "test-normalqueue")
public void receiveNormalQueue(String message)
{

    try {
        logger.info("message received in normal queue: " + message);
        throw new NullPointerException();

    } catch (Exception e) {

        logger.error(LoggingUtil.getStackTrace(e));;
    }

}

即使发生异常,消息也不会返回到队列中。
@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    factory.setConnectionFactory(getSQSConnectionFactory());
    factory.setConcurrency("1-2");
    factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
    return factory;
}

8
没有例外,你正在捕获所有内容。如果Spring需要回滚/不承认异常,就需要看到一个例外,但由于你正在捕获(并吞下)它,Spring认为一切都很好。 - M. Deinum
嗨,谢谢你的澄清。但是我对这种方法有一个疑问,如果我抛出异常,消息将被重新排队,但是监听器将再次拉回它并再次抛出异常形成循环,我该如何处理这种情况? - Bhargav
5
这是你希望在你的经纪人处处理的事情(我对SQS选项不是很熟悉),但通常你可以配置消息重新传递的次数,之后要么丢弃,要么移动到另一个通道/队列。 - M. Deinum
谢谢您的解释,我刚刚查了一下发现SQS中的DLQ与其完全相同的目的。 - Bhargav
2个回答

8

您需要在DMLC中使用事务。

使用Session.AUTO_ACKNOWLEDGEsetSessionTransacted(true)

如果监听器正常退出,则消息将被删除。如果监听器抛出异常,则消息将回滚到队列上。

您还可以在事务中使用客户端模式,但是您必须自己确认成功的消息。

您不必在SimpleMessageListenerContainer中使用事务,但仍然必须抛出异常才能重新排队消息。


嗨,我尝试使用SMLC,但它不起作用,你能否请看一下这个链接: https://dev59.com/8KHia4cB1Zd3GeqPUH3u - Bhargav
将会话设置为AUTO_ACKNOWLEDGE,将sessionTransacted设置为true对我很有效。 - Dragos Geornoiu

0
消息只有在监听器停止并与代理断开连接时才返回队列,您所描述的行为是在客户端的DefaultMessageListenerContainer上,它将消息分派到您的监听器并管理异常和重试,代理不知道这些处理,他只知道这些消息被分派到客户端,并等待确认。 如果在MessageConsumer的实现中存在类似重置或重新启动的方法,则取决于SQS的方法和功能。 您可以尝试使用JMS会话的recover()方法,但我认为这只会在客户端上重新启动交付。 https://docs.oracle.com/javaee/7/api/javax/jms/Session.html#recover-- 这不是一个好的做法,但如果您重新启动连接或DefaultMessageListenerContainer,则未确认的消息将返回代理,并重新启动交付。

我不太明白这里的代理是什么?你希望我如何解决这个问题?我们能否使用jmslistener来解决它? - Bhargav
这里使用的代理是 SQS,因为它提供了 JMS 接口。JMS 的原则是客户端必须处理消息,您能否解释一下为什么希望消息返回队列? - Hassen Bennour
1
你说 当出现异常时,我无法重新传递消息,因为你捕获了异常,所以消息被视为已消费而不是重新传递。如果你想要将消息重新传递给监听器,你必须在记录日志后抛出异常。 - Hassen Bennour
嗨,谢谢你澄清了。但我对这种方法有一个疑问,如果我抛出异常,消息将重新排队,但是监听器会再次拉回它并且再次抛出异常,形成一个循环,我该如何处理这种情况? - Bhargav

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接