簡體   English   中英

如何在 Spring-Retry 中計算 CircuitBreaker 的正確超時時間?

[英]How to calculate right timeouts for CircuitBreaker in Spring-Retry?

我了解@CircuitBreaker注釋應該如何工作,但不確定resetTimeout參數值。

我有一個應用程序每 10 秒不斷詢問其他外部服務。 每個請求可能需要 1-3 秒。 默認的 3 次嘗試沒問題,所以我想openTimeout 40 秒應該沒問題。 我決定將 80 秒設置為resetTimeout 據我了解文檔,如果 40 秒內發生 3 次故障,則電路將在 resetTimeout 參數(80 秒)中指定的時間段內打開。

在測試期間,我注意到如果電路打開並且另一個請求傳入,則不會調用外部服務。 沒關系,但我希望在resetTimeout (80s) 之后將調用一個從未發生過的真正服務。

奇怪的是,如果電路打開並且在 resetTimeout(80s) 期間沒有調用服務,則電路將重置。 恕我直言,彈簧應該比較當前時間和打開電路的故障,目前看起來它是將當前時間與上次請求進行比較。

我誤解了這個圖書館的想法嗎?

服務:

  package test;

import org.springframework.retry.annotation.CircuitBreaker;
import org.springframework.retry.annotation.Recover;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClientException;

@Component
class ConnectionService {

    @CircuitBreaker(include = { RestClientException.class }, openTimeout = 10_000, resetTimeout = 20_000)
    String doUpload(String payload) {
        if(payload.contentEquals("FAIL")) {
            throw new RestClientException("");
        }
        System.out.println("real service called");
        //callling external service....
        return payload;
    }

    @Recover
    public String recover(String payload) {
        return "recovered";
    }
}

測試:

package test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryListener;
import org.springframework.retry.annotation.EnableRetry;

@RunWith(MockitoJUnitRunner.class)
public class SpringRetryTest {

    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
            SpringRetryTest.TestConfiguration.class);
    ConnectionService connectionService = context.getBean(ConnectionService.class);

    @Test
    public void testCircuitBreaker() throws InterruptedException {

        incorrectStep();
        incorrectStep();
        incorrectStep();
        incorrectStep();
        incorrectStep();
        System.out.println();
        System.out.println();
        System.out.println();

        final long l = System.currentTimeMillis();
        correctStep(l);
        correctStep(l);
        correctStep(l);
        correctStep(l);
        correctStep(l);
        correctStep(l);
        correctStep(l);
        correctStep(l);
        correctStep(l);
        correctStep(l);
        correctStep(l);
        correctStep(l);
        correctStep(l);
        correctStep(l);
        correctStep(l);
        correctStep(l);
        correctStep(l);
        correctStep(l);
        correctStep(l);
        correctStep(l);
        correctStep(l);
        correctStep(l);

        //wait more than resetTimeout
        System.out.println();
        System.out.println();
        System.out.println();
        Thread.sleep(21_000L);
        correctStep(l);

    }

    private void incorrectStep() throws InterruptedException {
        doFailedUpload(connectionService);
        Thread.sleep(1_000L);
        System.out.println();
    }

    private void correctStep(final long l) throws InterruptedException {
        doCorrectUpload(connectionService);
        Thread.sleep(1_000L);
        printTime(l);
    }

    private void printTime(final long l) {
        System.out.println(String.format("%d ms after last failure", (System.currentTimeMillis() - l)));
    }

    private void doFailedUpload(ConnectionService externalService) throws InterruptedException {
        System.out.println("before fail");
        externalService.doUpload("FAIL");
        System.out.println("after fail");
        Thread.sleep(900);
    }

    private void doCorrectUpload(ConnectionService externalService) throws InterruptedException {
        System.out.println("before ok");
        externalService.doUpload("");
        System.out.println("after ok");
        Thread.sleep(900);
    }

    @Configuration
    @EnableRetry
    protected static class TestConfiguration {

        @Bean
        public ConnectionService externalService() {
            return new ConnectionService();
        }

        @Bean
        public RetryListener retryListener1() {
            return new RetryListener() {
                @Override
                public <T, E extends Throwable> boolean open(final RetryContext retryContext, final RetryCallback<T, E> retryCallback) {
                    System.out.println("----/ ---- open, retry count:" + retryContext.getRetryCount());
                    return true;
                }

                @Override
                public <T, E extends Throwable> void close(final RetryContext retryContext, final RetryCallback<T, E> retryCallback, final Throwable throwable) {
                    System.out.println("---------- close, retry count:" + retryContext.getRetryCount());
                }

                @Override
                public <T, E extends Throwable> void onError(final RetryContext retryContext, final RetryCallback<T, E> retryCallback, final Throwable throwable) {
                    System.out.println("onError, retry count:" + retryContext.getRetryCount());
                }

            };
        }

    }

}

我正在使用 osx 10.12.6、java 1.8.0_144 spring:4.2.3.RELEASE 和 spring-retry:1.2.1.RELEASE(我的同事也測試了 1.2.2,結果相同)

已發解決: https : //github.com/spring-projects/spring-retry/issues/99

它尚未發布,目前可作為快照使用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM