我正在尝试为消费者失败实施指数退避。为此,我有三个队列使用DLX:RETRY -> MAIN -> FAILED
。
MAIN
拒绝的任何内容都会FAILED
,RETRY
中添加的任何内容都会在每个消息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?
}
答案 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时,过期的消息可以在非过期消息之后排队,直到后者消耗或过期。