简体   繁体   English

Spring Retry Junit:使用自定义重试策略测试重试模板

[英]Spring Retry Junit: Testing Retry template with Custom Retry Policy

I'm trying to test a Retry template which is using a custom Retry Policy. 我正在尝试测试使用自定义重试策略的重试模板。 In order to do that, I'm using this examples: 为了做到这一点,我使用以下示例:

https://github.com/spring-projects/spring-retry/blob/master/src/test/java/org/springframework/retry/support/RetryTemplateTests.java#L57 https://github.com/spring-projects/spring-retry/blob/master/src/test/java/org/springframework/retry/support/RetryTemplateTests.java#L57

Basically, my goal is to test my retry logic when I got some specific http error status (for example an http 500 error status). 基本上,我的目标是在收到某些特定的http错误状态(例如,http 500错误状态)时测试重试逻辑。

This is the xml context for my junit: 这是我的junit的xml上下文:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:int="http://www.springframework.org/schema/integration"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int-http="http://www.springframework.org/schema/integration/http"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/integration
         http://www.springframework.org/schema/integration/spring-integration.xsd
         http://www.springframework.org/schema/integration/http
         http://www.springframework.org/schema/integration/http/spring-integration-http.xsd">

    <bean id="retryTemplate_test" class="org.springframework.retry.support.RetryTemplate">
        <property name="retryPolicy">
            <bean
                class="util.CustomRetryPolicy">
                <property name="maxAttempts" value="5" />
            </bean>
        </property>
        <property name="backOffPolicy">
            <bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
                <property name="initialInterval" value="1000" />
                <property name="multiplier" value="6" />
            </bean>
        </property>
    </bean>

</beans>

where CustomRetryPolicy is like: CustomRetryPolicy类似于:

public class CustomRetryPolicy extends ExceptionClassifierRetryPolicy {

    private String maxAttempts;

    @PostConstruct
    public void init() {

        this.setExceptionClassifier(new Classifier<Throwable, RetryPolicy>() {
            @Override
            public RetryPolicy classify(Throwable classifiable) {
                Throwable exceptionCause = classifiable.getCause();
                if (exceptionCause instanceof HttpStatusCodeException) {
                    int statusCode = ((HttpStatusCodeException) classifiable.getCause()).getStatusCode().value();
                    return handleHttpErrorCode(statusCode);
                }
                return neverRetry();
            }
        });
    }

    public void setMaxAttempts(String maxAttempts) {
        this.maxAttempts = maxAttempts;
    }


    private RetryPolicy handleHttpErrorCode(int statusCode) {
        RetryPolicy retryPolicy = null;
        switch(statusCode) {
        case 404 :
        case 500 :
        case 503 :
        case 504 :
            retryPolicy = defaultRetryPolicy();
            break;
        default :
            retryPolicy = neverRetry();
            break;
        }

        return retryPolicy;
    }

    private RetryPolicy neverRetry() {
        return new NeverRetryPolicy();
    }

    private RetryPolicy defaultRetryPolicy() {
        final SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy();
        simpleRetryPolicy.setMaxAttempts(Integer.valueOf(maxAttempts));
        return simpleRetryPolicy;
    }

}

And the Java class where I'm testing is: 我正在测试的Java类是:

@RunWith( SpringJUnit4ClassRunner.class )
@ContextConfiguration(locations = {"classpath:my_context_for_test.xml"})
public class RetryTemplateTest{


      @Autowired
      @Qualifier("retryTemplate_test")
      RetryTemplate retryTemplate_test;

    @Test
    public void testRetry() throws Throwable {
        Map<Class<? extends Throwable>, Boolean> r = new HashMap<>();
        r.put(HttpStatusCodeException.class, true);

            MockRetryCallback callback = new MockRetryCallback();
            callback.setAttemptsBeforeSuccess(5);            
            retryTemplate_test.execute(callback);

            assertEquals(5, callback.attempts);        
    }

    private static class MockRetryCallback implements RetryCallback<Object, HttpStatusCodeException> {

        private int attempts;

        private int attemptsBeforeSuccess;


        @SuppressWarnings("serial")
        @Override
        public Object doWithRetry(RetryContext status) throws HttpStatusCodeException {
            this.attempts++;
            if (this.attempts < this.attemptsBeforeSuccess) {
                System.out.println("I'm here: "+ this.attempts);
                throw new HttpStatusCodeException(HttpStatus.INTERNAL_SERVER_ERROR) {
                };
            }
            return null;
        }

        public void setAttemptsBeforeSuccess(int attemptsBeforeSuccess) {
            this.attemptsBeforeSuccess = attemptsBeforeSuccess;
        }
    }

}

What am I doing wrong? 我究竟做错了什么? My understanding is, using the callback, I'm mocking a response, and with that, I can handle (using my custom retry policy) that response. 我的理解是,使用回调,我正在模拟响应,并以此(可以使用自定义重试策略)处理该响应。 Also

[UPDATE] [更新]

If I try to replicate this junit , then I got the same exception. 如果我尝试复制这个junit ,那么我会遇到同样的异常。 Most specifically, it fails when try to instance the exception within the MockRetryCallback class right here : 最具体地说,当尝试在此处MockRetryCallback类中实例化异常时,它将失败:

    private Exception exceptionToThrow = new Exception();

I was able to get it working with this: 我能够使它与此一起工作:

@RunWith( SpringJUnit4ClassRunner.class )
@ContextConfiguration(locations = {"classpath:test-context.xml"})
public class HttpRetryTest{


      @Autowired
      @Qualifier("retryTemplate_test")
      RetryOperations retryTemplate_test;

    @Test
    public void testRetry() throws Throwable {
        Map<Class<? extends Throwable>, Boolean> r = new HashMap<>();
        r.put(HttpStatusCodeException.class, true);

            MockRetryCallback callback = new MockRetryCallback();
            MockRetryCallback.attemptsBeforeSuccess =5;            
            retryTemplate_test.execute(callback);

            assertEquals(5, MockRetryCallback.attempts);        
    }

    private static class MockRetryCallback implements RetryCallback<Object, HttpStatusCodeException> {

        private static int attempts;

        private static int attemptsBeforeSuccess;


        @SuppressWarnings("serial")
        @Override
        public Object doWithRetry(RetryContext status) throws HttpStatusCodeException {
            MockRetryCallback.attempts++;
            if (MockRetryCallback.attempts <= MockRetryCallback.attemptsBeforeSuccess) {
                System.out.println("I'm here: "+ MockRetryCallback.attempts);
                throw new HttpStatusCodeException(HttpStatus.INTERNAL_SERVER_ERROR) {
                };

            }
            return null;
        }
    }
}

For something much simpler, you might check out Failsafe : 为了更简单一些,您可以查看Failsafe

RetryPolicy<Object> retryPolicy = new RetryPolicy<>()
  .handleIf((HttpStatusCodeException e) -> e.getStatusCode().getValue() == 504)
  .withMaxAttempts(maxAttempts);

Failsafe.with(retryPolicy).get(() -> doSomething);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM