Spring Rabbit:确认模式 = 手动使用 RetryTemplate 不会从队列中删除消息

Spring Rabbit : Acknowledge mode = Manual with RetryTemplate does not remove the message from queue

我正在执行以下步骤:

  1. MessageListener 从队列 Q1 接收消息
  2. 验证消息
  3. 如果验证失败,调用channel.basicReject()并将其移动到死信队列
  4. 否则,假设电子邮件服务器出现故障。我用 requeue true 调用 channel.basicReject() 并抛出异常。它进入重试模板并在 maxAttempts 之后恢复(RepublishMessageRecoverer)并进入死信队列。

但它不会从 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 时抛出异常,则消息不会抛出重试模板和恢复器。是因为requeuing被拒绝的消息是新消息吗?

  1. 为什么 Q1 中的消息没有被删除?我该如何解决?

谢谢

您有责任在使用手动确认时进行确认(无论是否重试)。如果您的代码从不确认,则消息将(最终)重新排队;但您无权访问恢复器中的频道。

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

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

要有选择地 retry/requeue,您将需要自定义错误处理程序,请参阅