Spring Rabbit:Acknowledge mode = Manual with RetryTemplate不会从队列中删除消息

时间:2016-09-09 22:42:31

标签: rabbitmq spring-amqp spring-rabbit

我正在执行以下步骤:

  1. MessageListener从队列Q1
  2. 接收消息
  3. 验证消息
  4. 如果验证失败,请调用channel.basicReject()并将其移至死信队列
  5. 否则,让我们说,电子邮件服务器失败了。我将channel.basicReject()调用requeue为true并抛出异常。它将重试模板并在maxAttempts之后恢复(RepublishMessageRecoverer)并进入死信队列。
  6. 但它不会从Q1中删除该消息。

    public void onMessage(Message message, Channel channel) throws Exception {
            try {
                validateMessage();
    
                processMessage(message);
                channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
            }
            catch (DataValidationException ex){
                channel.basicReject(message.getMessageProperties().getDeliveryTag(),false);
    
            }
            catch(DownstreamAppException ex) {
                channel.basicReject(message.getMessageProperties().getDeliveryTag(),true);
                throw ex;
            }
        }
    
        void validMessage() {
            ..
            throw new DataValidationException();
        }
    
        void processMessage() {
    
            ...
            throw new DownstreamAppException();
        }
    

    我不想重新排队验证失败的邮件,但是想要重新排队那些由于某些下游应用程序失败而未处理的邮件。

    几个问题: 1.如果我没有在DownstreamAppException的catch中抛出异常,则消息不会抛出retryTemplate和recoverer。是因为重新排列被拒绝的消息是一条新消息吗?

    1. 为什么消息没有从Q1删除?我该如何解决?
    2. 由于

1 个答案:

答案 0 :(得分:0)

使用手动确认时(无论是否重试),您都有责任采取措施。如果您的代码永远不会消息,则消息将(最终)重新排队;但您无法访问恢复者中的频道。

真正的问题是你为什么要使用手册和ChannelAwareMessageListener?您的用例很简单。使用AUTO ackmode,容器将在成功时触发消息并在任何异常时拒绝它。

由于恢复者重新发布消息,这被认为是成功的,并且消息将被容器确认。

要有选择地重试/重新排队,您需要一个自定义的错误处理程序,请参阅this answer for more information