Spring Rabbit: режим подтверждения = вручную с RetryTemplate не удаляет сообщение из очереди

Я делаю следующие шаги:

  1. MessageListener получает сообщение из очереди Q1
  2. Подтвердите сообщение
  3. Если проверка не удалась, вызовите channel.basicReject () и переместите его в очередь недоставленных сообщений.
  4. Иначе, скажем, сервер электронной почты выходит из строя. Я вызываю channel.basicReject () со значением Requeue true и генерирую исключение. Он переходит к шаблону повтора и после 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, сообщение не будет выброшено retryTemplate и recoverer. Это потому, что запрос отклоненного сообщения является новым?

  1. Почему сообщение не удаляется из Q1? и как я могу это исправить?

Спасибо


person user3400371    schedule 09.09.2016    source источник


Ответы (1)


Вы несете ответственность за подтверждение при использовании ручного подтверждения (независимо от повторной попытки). Если ваш код не отвечает, сообщение (в конечном итоге) будет повторно поставлено в очередь; но у вас нет доступа к каналу в восстановителе.

Настоящий вопрос в том, почему вы используете ручные подтверждения и ChannelAwareMessageListener? Ваш вариант использования прост. Используя режим AUTO ackmode, контейнер подтвердит сообщение об успехе и отклонит его при любом исключении.

Поскольку средство восстановления повторно публикует сообщение, это считается успешным, и сообщение будет подтверждено контейнером.

Для выборочной повторной попытки / повторной постановки в очередь вам понадобится настраиваемый обработчик ошибок. Подробнее см. в этом ответе. информация.

person Gary Russell    schedule 10.09.2016
comment
Также см. этот ответ. - person Gary Russell; 10.09.2016