이 레퍼런스에서는 Spring Cloud Stream 프레임워크에서 제공해주는 에러 핸들링 방법들을 소개함. 

 

크게는 다음과 같은 방법들이 있음:

  • Retry
  • Drop failed messages
  • re-queue the message for re-processing or send the failed message to DLQ.

 

에러를 처리하는 방법은 Binder 구현체마다 다르니까 자세한 내용은 각 Binder 마다 레퍼런스를 참고해야함:

  • 메시지를 처리하는 핸들러에서 에러가 발생하면 에러는 binder 에게 전파된다.

 

이 글에서 소개하는 에러 핸들링 내용은 Reactive Function Bean 들에서는 적용이 안됨. 오로지 imperative functions 에서만 적용이 된다:

  • Reactive Function 의 경우 데이터 시퀀스를 사용자가 정의한 함수형 빈으로 전달해주는 역할만 한다. reactive API 는 풍부한 에러 처리 기능을 제공해주니까 그것에 맞춰서 각각 구현하면 된다고 함.
  • imperative functions 는 프레임워크에서 실행을 해줄 수 있으니까 에러 핸들링 기능을 적용해줄 수 있음.

 

1. Drop Failed Messages

에러가 발생했을 때 어떻게 처리할 건지 설정을 등록하지 않는다면 기본적으로는 실패한 메시지에 대해서 logging 되고 drop 될 것이다.

 

2. Handle Error Messages

특정 바인딩에서 에러가 났을 때 이를 처리하는 커스텀 에러 핸들러로 처리하도록 할 수 있다:

  • 이 경우에는ErrorMessage 를 받게 되는데 여기에는 에러에 대한 정보와 원본 메시지 모두 들어가있다.
@Bean
public Consumer<ErrorMessage> myErrorHandler() {
    return v -> {
        // send SMS notification code
    };
}

 

커스텀 에러 핸들러는 어떤 바인딩의 에러를 처리할 것인지에 대한 매핑 설정을 해줘야 사용할 수 있다:

  • 예시로 uppercase-in-0 바인딩의 에러를 처리하고 싶으면 spring.cloud.stream.bindings.uppercase-in-0.error-handler-definition=myErrorHandler 이렇게 작성하면 된다.

 

3. DLQ - Dead Letter Queue

메시지를 처리하다가 에러가 났을 때 이를 핸들링 하는 전략으로는 DLQ (Dead Letter Queue) 를 이용하는 방벙이 있다:

  • DLQ 에 저장해서 reprocessing or auditing and reconciliation 을 할 수 있음.
  • DLQ 에 저장하고 이후 메시지는 계속해서 처리할 수 있다. 에러 메시지 때문에 블라킹 되지 않도록 하면서. 

 

DLQ 를 사용하는 예시를 보자:

  • 프로퍼티 설정 중에 auto-bind-dlq=true 를 설정하면서 DLQ 처리를 활성화 시킬 수 있다.
  • DLQ 를 활성화 시킬 땐 group 을 설정해줘야한다. 이 이름과 Destination 을 바탕으로 DLQ 에 저장될 토픽이 만들어지고 저장한다. 여기서는 uppercase.myGroup.dlq 라는 토픽이 만들어질거임.
@SpringBootApplication
public class SimpleStreamApplication {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(SimpleStreamApplication.class,
          "--spring.cloud.function.definition=uppercase",
          "--spring.cloud.stream.bindings.uppercase-in-0.destination=uppercase",
          "--spring.cloud.stream.bindings.uppercase-in-0.group=myGroup",
          "--spring.cloud.stream.rabbit.bindings.uppercase-in-0.consumer.auto-bind-dlq=true"
        );
    }

    @Bean
    public Function<Person, Person> uppercase() {
        return personIn -> {
           throw new RuntimeException("intentional");
          });
        };
    }
}

 

기본적으로 DLQ 에 저장하기 전까지 재시도를 하는데 재시도를 하지 않도록 설정하려면 --spring.cloud.stream.bindings.uppercase-in-0.consumer.max-attempts=1 로 설정하면 된다. (위 예시 기준)

 

4. Retry Template

에러가 났을 때 RetryTemplate 를 이용해서 재시도 하도록 설정할 수 있다.

  • RetryTemplate 는 Spring Retry 라이브러리를 이용하는 것.

 

RetryTemplate 에서 설정할 수 있는 주요 설정은 다음과 같다:

  • maxAttempts: Retry 최대 시도 횟수. 기본값 3
  • backOffInitialInterval: Retry 를 할 때 초기 backoff. 기본값은 1000ms
  • backOffMaxInterval: 최대 backoff interval. 기본값은 10000ms
  • backOffMultiplier: backoff multiplier. 기본값은 2
  • defaultRetryable: retryableException 이 아님에도 불구하고 재시도를 기본적으로 할 것인지 여부. 기본값은 true
  • retryableExceptions: retryableException 에 등록을 하기 위한 것. 예시: spring.cloud.stream.bindings.input.consumer.retryable-exceptions.java.lang.IllegalStateException=false 기본값은 empty 임.

 

RetryTemplate 를 커스텀하게 만들고 싶다면 다음과 같이 하면 된다. @Bean 을 사용하지 않아도 됨. 

@StreamRetryTemplate
public RetryTemplate myRetryTemplate() {
    return new RetryTemplate();
}

 

References

https://docs.spring.io/spring-cloud-stream/reference/spring-cloud-stream/overview-error-handling.html

'Spring > Spring Cloud Stream' 카테고리의 다른 글

Resetting Offsets  (0) 2024.01.16
Binder Abstraction  (0) 2024.01.16
Producing and Consuming Messages: Spring Cloud Stream  (0) 2024.01.12

+ Recent posts