使用Spring-Retry指定特定于例外的退避策略

Zim*_*oot 8 java spring exception-handling spring-retry

我正在使用Spring-Retry进行一些数据库操作.在SQLRecoverableException我重试三次(这假设导致异常的任何内容是非瞬态的,如果它失败了三次),在SQLTransientException我无限期重试(程序无法做任何事情而无法访问数据库,所以它也可以继续重试,直到用户决定重新启动服务器),并且在任何其他异常时我都不会重试.我使用指数退避策略,基本重试为100毫秒,最大重试次数为30,000毫秒.

private static final int MAX_RECOVERABLE_RETRIES = 3;
private static final long INITIAL_INTERVAL = 100;
private static final long MAX_INTERVAL = 30 * 1000;
private static final double MULTIPLIER = 2.0;

public static RetryTemplate databaseTemplate() {
    RetryTemplate template = new RetryTemplate();
    ExceptionClassifierRetryPolicy retryPolicy = new ExceptionClassifierRetryPolicy();
    Map<Class<? extends Throwable>, RetryPolicy> policyMap = new HashMap<>();
    NeverRetryPolicy baseException = new NeverRetryPolicy();
    SimpleRetryPolicy recoverablePolicy = new SimpleRetryPolicy();
    recoverablePolicy.setMaxAttempts(MAX_RECOVERABLE_RETRIES);
    AlwaysRetryPolicy transientPolicy = new AlwaysRetryPolicy();
    policyMap.put(Exception.class, baseException);
    policyMap.put(SQLRecoverableException.class, recoverablePolicy);
    policyMap.put(SQLTransientException.class, transientPolicy);
    retryPolicy.setPolicyMap(policyMap);
    template.setRetryPolicy(retryPolicy);
    ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
    backOffPolicy.setInitialInterval(INITIAL_INTERVAL);
    backOffPolicy.setMaxInterval(MAX_INTERVAL);
    backOffPolicy.setMultiplier(MULTIPLIER);
    template.setBackOffPolicy(backOffPolicy);
    return template;
}
Run Code Online (Sandbox Code Playgroud)

理想情况下,我想对所有人使用100ms的固定退避SQLRecoverableExceptions,并且只应用指数退避策略SQLTransientExceptions.我可以通过嵌套重试来实现这一点,但这将大大增加代码复杂性 - 如果没有其他选项,我宁愿简单地将指数退避应用于两者SQLRecoverableExceptionSQLTransientException异常.

有没有办法让我使用单个重试模板将不同的退避策略应用于不同的异常?

oai*_*oud 6

确实,ExceptionClassifierRetryPolicy是要走的路。我没有设法让它与policyMap尽管一起工作。

这是我如何使用它:

@Component("yourRetryPolicy")
public class YourRetryPolicy extends ExceptionClassifierRetryPolicy
{
    @PostConstruct
    public void init()
    {
        final SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy();
        simpleRetryPolicy.setMaxAttempts( 3 );

        this.setExceptionClassifier( new Classifier<Throwable, RetryPolicy>()
        {
            @Override
            public RetryPolicy classify( Throwable classifiable )
            {
                    if ( classifiable instanceof YourException )
                    {
                            return new NeverRetryPolicy();
                    }
                    // etc...
                    return simpleRetryPolicy;
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您只需在重试模板上设置它:

@Autowired
@Qualifier("yourRetryPolicy")
private YourRetryPolicy yourRetryPolicy;

//...

RetryTemplate retryTemplate = new RetryTemplate();
retryTemplate.setRetryPolicy( yourRetryPolicy );
Run Code Online (Sandbox Code Playgroud)