如何处理消费者异常作为确认?

时间:2017-01-04 11:17:34

标签: java spring rabbitmq spring-amqp

我正在尝试为消费者失败实施指数退避。为此,我有三个队列使用DLX:RETRY -> MAIN -> FAILED

MAIN拒绝的任何内容都会FAILEDRETRY中添加的任何内容都会在每个消息TTL之后进入MAIN。消费者从MAIN收到。

我已实施ErrorHandler并将其设置在SimpleRabbitListenerContainerFactory上。此处理程序要么计算新的TTL并将消息发送到RETRY队列,要么抛出AmqpRejectAndDontRequeueException如果不可能或重试超过,则将其DLX转移到FAILED 。问题是,我无法弄清楚如何摆脱原始信息。

据我所知,我必须确认它,但Channel在错误处理程序中不可用,并且没有其他例外可以触发ack。

如果我删除了MAIN -> FAILED DLX并切换为手动向FAILED添加邮件,那么如果这不起作用我就丢失了邮件。

@Override
public void handleError(Throwable t) {
  log.warn("Execution of Rabbit message listener failed.", t);

  try {
    queueForExponentialRetry(((ListenerExecutionFailedException) t).getFailedMessage());
    // what to do here?
  } catch (RuntimeException ex) {
    t.addSuppressed(ex);
    log.error("Not requeueing after failure", t);
    throw new AmqpRejectAndDontRequeueException(t);
  }
  // or here?
}

1 个答案:

答案 0 :(得分:1)

我想我立刻找到了答案。之前错过了因为我从错误的地方扔了。

@Override
public void handleError(Throwable t) {
  log.warn("Execution of Rabbit message listener failed.", t);

  try {
    queueForExponentialRetry(((ListenerExecutionFailedException) t).getFailedMessage());
  } catch (RuntimeException ex) {
    t.addSuppressed(ex);
    log.error("Not requeueing after failure", t);
    throw new AmqpRejectAndDontRequeueException(t);
  }

  throw new ImmediateAcknowledgeAmqpException("Queued for retry");
}
  

<强> ImmediateAcknowledgeAmqpException

     

侦听器实现的特殊例外,它希望在没有回滚的情况下立即(即尽快)确认当前批次的消息,并且不会在当前事务中消耗任何更多消息。

这应该是安全的,因为我没有使用批次或交易,只有发布者返回。

旁注:我还应该知道,指数退避实际上无法正常工作:

  

虽然消费者永远不会看到过期的消息,但只有当过期的消息到达队列的头部时,它们才会被丢弃(或死信)。设置每个队列TTL时这不是问题,因为过期的消息总是在队列的头部。但是,在设置每条消息的TTL时,过期的消息可以在非过期消息之后排队,直到后者消耗或过期。