当前位置: 首页 > 知识库问答 >
问题:

如何用spring重试包装耗尽重试时的异常

尤钱明
2023-03-14

上下文:

我正在使用spring-retry重试restTemplate调用。

restTemplate调用是从kafka侦听器调用的。kafka侦听器还被配置为在出错时重试(如果在过程中抛出任何异常,而不仅仅是restTemplate调用)。

目标:

当错误来自已耗尽的重试模板时,我想防止kafka重试。

实际行为:

当retryTemplate用尽所有重试时,将引发原始异常。从而阻止我识别RetryTemplate是否重试了该错误。

所需行为:

当retryTemplate用尽所有重试时,将原始异常包装在RetryEvertestedException中,这将允许我将其从kafka重试中列入黑名单。

问题:

我怎么能做这种事?

谢谢

编辑

RetryTemplate配置:

RetryTemplate retryTemplate = new RetryTemplate();

FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
backOffPolicy.setBackOffPeriod(1000);
retryTemplate.setBackOffPolicy(backOffPolicy);

Map<Class<? extends Throwable>, Boolean> retryableExceptions = new HashMap<>();
retryableExceptions.put(FunctionalException.class, false);
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(3, retryableExceptions, true, true);
retryTemplate.setRetryPolicy(retryPolicy);

retryTemplate.setThrowLastExceptionOnExhausted(false);

Kafka错误处理程序

public class DefaultErrorHandler implements ErrorHandler {

@Override
public void handle(Exception thrownException, ConsumerRecord<?, ?> data) {
    Throwable exception = Optional.ofNullable(thrownException.getCause()).orElse(thrownException);

    // TODO if exception as been retried in a RetryTemplate, stop it to prevent rollback and send it to a DLQ
    // else rethrow exception, it will be rollback and handled by AfterRollbackProcessor to be retried
    throw new KafkaException("Could not handle exception", thrownException);
   }
}

听众Kafka:

@KafkaListener
public void onMessage(ConsumerRecord<String, String> record) {
    retryTemplate.execute((args) -> {
        throw new RuntimeException("Should be catched by ErrorHandler to prevent rollback");
    }
    throw new RuntimeException("Should be retried by afterRollbackProcessor");
}

共有1个答案

东门楚
2023-03-14

只需使用SimpleRetryPolicy配置侦听器重试模板,该模板配置为将RetryEvertedException分类为不可重试。

确保将TraverSecauss属性设置为true,因为容器将所有侦听器异常包装在ListenerExecutionFailedException中。

/**
 * Create a {@link SimpleRetryPolicy} with the specified number of retry
 * attempts. If traverseCauses is true, the exception causes will be traversed until
 * a match is found. The default value indicates whether to retry or not for exceptions
 * (or super classes) are not found in the map.
 *
 * @param maxAttempts the maximum number of attempts
 * @param retryableExceptions the map of exceptions that are retryable based on the
 * map value (true/false).
 * @param traverseCauses is this clause traversable
 * @param defaultValue the default action.
 */
public SimpleRetryPolicy(int maxAttempts, Map<Class<? extends Throwable>, Boolean> retryableExceptions,
        boolean traverseCauses, boolean defaultValue) {

编辑

使用

template.execute((args) -> {...}, (context) -> throw new Blah(context.getLastThrowable()));
 类似资料:
  • 问题内容: 我有一个以开头的循环。正常情况下,它可以正常运行,但有时由于网络条件而失败。目前,我已对其进行了设置,以便在失败时,它将在except子句中(继续到的下一个数字)。 我是否可以将相同的数字重新分配给循环并再次执行失败的循环? 问题答案: 做一个内部的for循环,把你的代码中,并突破从只有当你的代码的成功循环。

  • 我以前非常成功地使用了JMS的Spring集成,但是我们现在使用RabbitMQ/AMQP,并且在错误处理方面有一些问题。 我有一个int-amqp: inbinding-Channel适配器,带有一个设置为接收任何异常的错误通道,这里有一个错误转换器类检查失败的消息的原因异常。然后根据异常的类型:- > 抑制异常并转换为JSON对象,该对象可以作为解释故障的业务回复转到AMQP出站通道适配器。在

  • 我放了一个简单的重试,因为操作很少会失败。下面是简化的代码。方法< code>putObject可能会意外引发异常,在这种情况下,重试应该允许再次调用此方法。有可能为此编写一个JUnit测试吗?我知道使用Mockito library我们可以强制抛出一个调用方法的异常,但是如何强制这个异常只抛出一次呢? 测试类:

  • 问题内容: 我有一个Spring AMQP消息监听器正在运行。 如您所见,在处理过程中可能会出现异常。我想重试,因为Catch块中有特定错误。我无法通过onMessage中的异常。如何告诉RabbitMQ有异常并重试? 问题答案: 由于不允许抛出已检查的异常,因此可以将异常包装在中并重新抛出。 但是请注意,这可能导致消息无限期地重新发送。这是这样的: RabbitMQ支持拒绝消息并要求代理重新排队