somoly.tistory.com
Published 2023. 3. 14. 17:31
Retrying Feign Calls SpringBoot

Retrying Feign Calls

 

소개

 

- REST 엔드포인트를 통해 외부 서비스를 호출하는 것은 Feign과 같은 라이브러리에서 매우 간단하게 작성할 수 있습니다.
- 그러나 이러한 호출 중에 많은 문제가 발생할 수 있습니다. 이러한 문제의 대부분은 무작위적이거나 일시적인 것입니다.
- 여기에서는 실패한 호출을 다시 시도하고 보다 탄력적인 REST 클라이언트를 만드는 방법에 대해 알아봅니다.

 

Spring Cloud OpenFeign 환경설정

dependencies {
    implementation("org.springframework.boot:spring-boot-starter")
    implementation("org.springframework.cloud:spring-cloud-starter-openfeign")
}

dependencyManagement {
    imports {
        mavenBom("org.springframework.cloud:spring-cloud-dependencies:2022.0.1")
    }
}

 

# application.properties
spring.cloud.openfeign.compression.request.enabled=true
spring.cloud.openfeign.compression.response.enabled=true
spring.cloud.openfeign.client.config.default.logger-level=full
spring.cloud.openfeign.client.config.default.connect-timeout=5000
spring.cloud.openfeign.client.config.default.read-timeout=5000

 

Feign Retryer

Default Implementation

- Feign은 재시도 인터페이스의 합리적인 기본 구현을 제공합니다.
- 주어진 횟수만큼만 재시도하고, 일정 시간 간격으로 시작한 다음, 재시도할 때마다 지정된 최대값까지 간격을 늘립니다.
- 시작 간격을 1초, 최대 간격을 3초, 최대 시도 횟수를 3회로 정의해 보겠습니다:

@Configuration(proxyBeanMethods = false)
public class CustomOpenFeignConfig {
    @Bean
    public Retryer feignRetryer() {
        return new Retryer.Default(1000, TimeUnit.SECONDS.toMillis(3), 3);
    }
}




No Retrying

- Feign이 호출을 재시도하지 않도록 하려면 클라이언트 빌더에 Retryer.NEVER_RETRY 구현을 제공하면 됩니다. 

- 그러면 매번 예외를 전파하기만 하면 됩니다.

@Configuration(proxyBeanMethods = false)
public class CustomOpenFeignConfig {
    @Bean
    public Retryer feignNoRetryer() {
        return Retryer.NEVER_RETRY;
    }
}



Creating Retryable Exceptions

- 이전에는 호출을 재시도하는 빈도를 제어하는 방법을 배웠습니다.
- 이제 호출을 재시도할 때와 단순히 예외를 던질 때를 제어하는 방법을 살펴보겠습니다.

 


ErrorDecoder 와 RetryableException

- 잘못된 응답을 받으면 Feign은 이를 어떻게 처리할지 결정하는 ErrorDecoder 인터페이스의 인스턴스로 전달합니다.
- 가장 중요한 것은 디코더가 예외를 RetryableException의 인스턴스에 매핑하여 Retryer가 호출을 재시도할 수 있도록 한다는 점입니다.
- ErrorDecoder의 기본 구현은 응답에 "Retry-After" 헤더가 포함된 경우에만 RetryableException 인스턴스를 생성합니다. 가장 일반적으로 503 서비스 사용 불가 응답에서 찾을 수 있습니다.
- 이는 좋은 기본 동작이지만 때로는 더 유연해야 할 때도 있습니다.
- 예를 들어, 때때로 500 내부 서버 오류로 무작위로 응답하는 외부 서비스와 통신하고 있는데 이를 해결할 수 있는 권한이 없는 경우가 있습니다.
- 우리가 할 수 있는 일은 다음 번에는 통화가 성공할 것이라는 것을 알기 때문에 통화를 다시 시도하는 것입니다.
- 이를 위해서는 사용자 정의 ErrorDecoder 구현을 작성해야 합니다.



Custom Error Decoder 생성

- 사용자 정의 디코더에서 구현해야 하는 메서드는 decode 하나뿐입니다.
- 이 메서드는 두 개의 인자, 즉 String 메서드 키와 Response 객체를 받습니다.
- 이 메서드는 예외를 반환하는데, 이 예외가 RetryableException의 인스턴스이거나 구현에 따라 다른 예외인 경우 예외를 반환합니다.
- 디코딩 메서드는 단순히 응답의 상태 코드가 500보다 높거나 같은지 확인합니다.
- 이 경우 RetryableException을 생성합니다. 그렇지 않은 경우, FeignException 클래스의 errorStatus 팩토리 함수로 생성된 기본 FeignException을 반환합니다:

public class Custom5xxErrorDecoder implements ErrorDecoder {
    @Override
    public Exception decode(String methodKey, Response response) {
        FeignException exception = feign.FeignException.errorStatus(methodKey, response);
        int status = response.status();
        if (status >= 500) {
            return new RetryableException(
              response.status(),
              exception.getMessage(),
              response.request().httpMethod(),
              exception,
              null,
              response.request());
        }
        return exception;
    }
}



Custom Error Decoder 설정 추가

@Configuration(proxyBeanMethods = false)
public class CustomOpenFeignConfig {
    @Bean
    public ErrorDecoder custom5xxErrorDecoder() {
        return new Custom5xxErrorDecoder();
    }
}

 

profile

somoly.tistory.com

@RxCats

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!