토리맘의 한글라이즈 프로젝트 logo 토리맘의 한글라이즈 프로젝트

resilience4j 공식 레퍼런스를 한글로 번역한 문서입니다.

전체 목차는 여기에 있습니다.

목차


Feign을 위한 Resilience4j 데코레이터. resilience4j-feign을 사용하면 HystrixFeign과 유사하게 feign 프레임워크에 CircuitBreaker, RateLimiter같은 “fault tolerance” 패턴들을 쉽게 통합할 수 있다.


Current Features


Decorating Feign Interfaces

Resilience4jFeign.builder는 feign의 fault tolerance 인스턴스를 생성하기 위한 메인 클래스다.
Feign.builder를 상속하고 있으며, 커스텀 InvocationHandlerFactory를 추가할 때를 빼고는 같은 방법으로 설정할 수 있다. Resilience4jFeign은 자체 InvocationHandlerFactory를 사용해서 데코레이터를 적용한다. 데코레이터는 FeignDecorators 클래스를 사용해서 빌드할 수 있다. 여러 데코레이터를 결합해도 된다.
다음 예제는 RateLimiter와 CircuitBreaker를 사용해서 feign 인터페이스를 데코레이트하는 방법을 보여준다:

public interface MyService {
        @RequestLine("GET /greeting")
        String getGreeting();
            
        @RequestLine("POST /greeting")
        String createGreeting();
}

CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("backendName");
RateLimiter rateLimiter = RateLimiter.ofDefaults("backendName");
FeignDecorators decorators = FeignDecorators.builder()
                                 .withRateLimiter(rateLimiter)
                                 .withCircuitBreaker(circuitBreaker)
                                 .build();
MyService myService = Resilience4jFeign.builder(decorators).target(MyService.class, "http://localhost:8080/");

MyService 인스턴스에 있는 메소드를 호출하면 CircuitBreaker와 RateLimiter가 차례대로 호출된다.
이런 메커니즘 중 하나가 작동되면 CircuitBreakerOpenException이나 RequestNotPermitted같은 메커니즘에 따른 RuntimeException이 발생한다 (힌트: 이 예외들은 FeignException 클래스를 상속하지 않았다).

4c8e8ba-feign-decorators

이 다이어그램은 데코레이터가 쌓이는 방식을 보여주고 있다.


Ordering of Decorators

데코레이터가 적용되는 순서는 선언한 순서에 따라 다르다.
선언한 순서에 따라 동작이 달라지기 때문에 FeignDecorators를 빌드할 땐 반드시 주의해야 한다.

FeignDecorators decoratorsA = FeignDecorators.builder()
                                         .withCircuitBreaker(circuitBreaker)
                                         .withRateLimiter(rateLimiter)
                                         .build();
                                         
FeignDecorators decoratorsB = FeignDecorators.builder()
                                         .withRateLimiter(rateLimiter)
                                         .withCircuitBreaker(circuitBreaker)
                                         .build();

decoratorsA에선 RateLimiter가 CircuitBreaker보다 먼저 호출된다. 즉, CircuitBreaker가 열려 있더라도 RateLimiter는 호출 속도를 제한한다. decoratorsB는 정반대다. CircuitBreaker가 열리면 RateLimiter는 더 이상 시행되지 않는다.


Fallback

예외가 발생하면 호출할 폴백을 정의할 수 있다. 예외는 HTTP 요청에 실패했을 때 발생할 수도 있지만, CircuitBreaker 등의 FeignDecorators 중 하나가 활성화됐을 때도 발생할 수 있다.

public interface MyService {
        @RequestLine("GET /greeting")
        String greeting();
}

MyService requestFailedFallback = () -> "fallback greeting";
MyService circuitBreakerFallback = () -> "CircuitBreaker is open!";
CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("backendName");
FeignDecorators decorators = FeignDecorators.builder()
                                 .withFallback(requestFailedFallback, FeignException.class)
                                 .withFallback(circuitBreakerFallback, CircuitBreakerOpenException.class)
                                 .build();
MyService myService = Resilience4jFeign.builder(decorators).target(MyService.class, "http://localhost:8080/", fallback);

이 예시에선 requestFailedFallbackFeignException이 발생하면 (보통 HTTP 요청에 실패했을 때) 호출되지만, circuitBreakerFallbackCircuitBreakerOpenException이 발생했을 때만 호출된다. 폴백을 필터링하는 더 다양한 방법은 FeignDecorators 클래스를 확인해봐라.

모든 폴백은 “target”(Resilience4jFeign.Builder#target) 메소드에 선언한 타입과 동일한 인터페이스를 구현해야 한다. 그렇지 않으면 IllegalArgumentException이 발생한다.
폴백을 여러 개 할당해서, 이전 폴백이 실패하면 같은 Exception을 다음 폴백을 통해 처리하도록 만들 수도 있다.

필요하면 폴백에서 던져진 예외를 컨슘해도 된다. 예외에 따라 다른 동작을 실행해야 하는 경우나 단순히 예외를 로깅할 때도 유용할 거다.
단, 이런 류의 폴백은 예외가 발생할 때마다 인스턴스를 만들게 된다.

public interface MyService {
        @RequestLine("GET /greeting")
        String greeting();
}

public class MyFallback implements MyService {
        private Exception cause;

        public MyFallback(Exception cause) {
            this.cause = cause;
        }

        public String greeting() {
            if (cause instanceOf FeignException) {
                return "Feign Exception";
            } else {
                return "Other exception";
            }
        }
}

FeignDecorators decorators = FeignDecorators.builder()
            .withFallbackFactory(MyFallback::new)
            .build();

전체 목차는 여기에 있습니다.

<< >>

TOP