我可以很好地接收来自我的服务总线订阅的消息,但是当我的监听器发生异常时,似乎最终将状态=已修改并且undeliverableHere = true的处置帧发送到服务总线。服务总线的docs表示它不支持amqp Modified处置。
消息以服务总线中的延迟状态结束,我无法弄清楚如何将消息轻推回活动。
JMS配置:
@Bean
public ConnectionFactory jmsConnectionFactory(MessageStoreProperties properties) throws UnsupportedEncodingException {
JmsConnectionFactory connectionFactory = new JmsConnectionFactory(properties.getUrlString());
connectionFactory.setClientID(clientId);
connectionFactory.setUsername(properties.getUsername());
connectionFactory.setPassword(properties.getPassword());
connectionFactory.setRedeliveryPolicy(redeliveryPolicy());
return new CachingConnectionFactory(connectionFactory);
}
@Bean
public JmsDefaultRedeliveryPolicy redeliveryPolicy() {
JmsDefaultRedeliveryPolicy policy = new JmsDefaultRedeliveryPolicy();
policy.setMaxRedeliveries(50);
return policy;
}
@Bean
public JmsListenerContainerFactory topicContainerFactory(ConnectionFactory connectionFactory) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setSubscriptionDurable(true);
factory.setPubSubDomain(true);
factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
return factory;
}
监听器:
@JmsListener(destination = "crm-customer-event/subscriptions/test-sub", containerFactory = "topicContainerFactory")
public void receiveCustomerEvent(@Payload ExecutionContextDTO dto) {
logger.debug("Got payload: " + dto);
throw new RuntimeException("Oops");
}
以下是我在日志中看到的内容:
邮件传输开始
[299309872:1] <- Transfer{handle=0, deliveryId=0, deliveryTag=\x97\x1c\x87\x04\xb7\xea\x86@\xb3n\xbd\x9fg\x81\x00\x11, messageFormat=0, settled=null, more=false, rcvSettleMode=null, state=null, resume=false, aborted=false, batchable=true} (16695) "\x00Sp\xc0\x0a\x05@@p.........
抛出异常,然后JMS在本地重新传递消息50次(为什么会这样做?)
我之后看到的下一个amqp协议框架是
[299309872:1] -> Disposition{role=RECEIVER, first=0, last=0, settled=true, state=Modified{deliveryFailed=true, undeliverableHere=true, messageAnnotations=null}, batchable=false}
在我看来,最后一个Disposition帧导致消息进入Deferred状态。消息上还有一个锁定令牌。即使在TTL通过时,消息仍然停留在订阅中,并且通过REST api对其没有任何帮助。我尝试解锁它(使用PUT)并删除它(使用DELETE)。我也尝试过使用REST api接收它(包括PeekLock和接收和删除变种),看起来它们似乎并不存在。我在订阅上设置了选项,可以在到期后自动将消息移动到死信队列,并且它们永远不会被移动。
使qk发生的qpid-jms的代码是here,并且看起来这部分库不是要扩展的,否则我将自己的实现返回一个不同的确认。
如何获得qpid / JMS
答案 0 :(得分:2)
首先,JMS规范正确地指出,对于从MessageListener回调中抛出的异常,它确实是一个应用程序编程错误,您的应用程序应该自己处理这些错误。
其次,客户端正在使用正确的处理方式来指示消息未能传递到此客户端,远程应支持AMQP 1.0规范中列出的所有处置,我与Microsoft联系并请求他们实现规范更加紧密。
要解决上述问题,您可以在客户端确认模式下接收消息,当您拦截正在抛出的异常时,您可以使用this JIRA Issue中描述的机制配置消息确认。
代码如下所示:
message.setIntProperty("JMS_AMQP_ACK_TYPE", 2);
message.acknowledge();
模式定义为:
ACCEPTED = 1;
REJECTED = 2;
RELEASED = 3;
MODIFIED_FAILED = 4;
MODIFIED_FAILED_UNDELIVERABLE = 5;