이 레퍼런스에서는 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
'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 |