Retry 예제

2021. 8. 7. 23:31SpringBoot Monitoring/SpringBoot Resilience4j

반응형

resilience4j-retry 예제를 작성하기 전에 한 가지 시나리오를 생각해 보자.

사용자가 주문을 할때 가장 중요한 부분은 결제 일 것이다. 그런데 시스템 운영 중 중요한 오류가 있어서 서버에 소스를 반영하고 재기동해야 한다고 하면 그 시간 동안 회사는 많은 손해가 발생할 것입니다.

 

만약 소스를 반영하고 서버 재기동 까지 1분 안에 가능하다고 한다면 사용자가 주문이 잠시 느려지더라도 결제까지 정상적으로 실행할 수 있을 것이다.

이렇게 되면 서비스 제공자 입장에서는 정상적으로 서비스를 제공하면서 큰 문제를 막을 수 있을 것이다.

 

극단적인 시나리오 일수 있겠지만 실제로 서비스를 운영하다 보면 저러한 문제들이 있을 것입니다.

Retry는 이러한 문제를 해결 하기에 적합하다는 생각이 듭니다.

 

소스는 아래 사이트에서 받으실 수 있습니다.

https://github.com/roopy1210/spring-boot-resilience4j

 

GitHub - roopy1210/spring-boot-resilience4j

Contribute to roopy1210/spring-boot-resilience4j development by creating an account on GitHub.

github.com

 

[application.yml]

spring:
  application.name: order-service
  output.ansi.enabled: always

server:
  port: 7070

management.endpoints.web.exposure.include: '*'
management.endpoint.health.show-details: always

# Spring actuator 에 circuitbreaker 정보를 표시하기 위한 설정
management.health.circuitbreakers.enabled: true

#-------------------------------------------------------------
# Retry Configuration
#-------------------------------------------------------------
# 설정의 의미는 총 30초 동안 10초 간격으로 서비스 호출을 3번 
# 한다는 의미이다.
#-------------------------------------------------------------
  retry:
    instances:
      orderService:
        maxRetryAttempts: 3
        waitDuration: 10s

주석에도 설명 되어 있지만 위의 설정은 30초 동안 10초 간격으로 서비스 호출을 3번 한다는 의미이다.

 

[RetrySericeImpl]

package com.roopy.service.impl;

import com.roopy.service.OrderService;
import io.github.resilience4j.retry.annotation.Retry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
@Qualifier("retryService")
public class RetryServiceImpl implements OrderService {

    Logger logger = LoggerFactory.getLogger(OrderService.class);

    @Autowired
    private RestTemplate restTemplate;

    private int attempts = 1;

    @Override
    @Retry(name = "orderService", fallbackMethod = "retryFallback")
    public String makeOrder() {
        logger.info("결제서비스 호출 횟수 : " + attempts++);
        return restTemplate.getForObject("http://localhost:7071/pay", String.class);
    }

    public String retryFallback(Throwable t) {
        attempts = 1;
        logger.error("Retry fallback, cause - {}", t.toString());
        return "[Retry] 결제서비스 호출 중 오류가 발생 하였습니다.";
    }
}

주문 서비스에서는 결제 서비스를 Rest방식으로 호출하는데 이때 application.yml 에 설정된 총 30초 동안 10초에 한 번씩 결제 서비스를 호출하고 3번 호출되기 전에 결제 서비스가 실행되면 정상적으로 주문처리가 될 것이다.

 

[테스트 결과]

첫 번째로 payment-service 서버는 실행하지 않은 상태에서 수행 결과 실패

두 번째로 payment-service 서버 실행 후 재 수행 결과 성공

콘솔 로그

로그 결과를 보면 1번 결과는 payment-service 서버가 실행되지 않은 상태에서 설정 파일에서 설정한 maxRetryAttempts: 3 횟수 만큼 실행 후 오류를 발생하는 것을 확인할 수 있습습니다. 2번 결과는 payment-service 실행 후 다시 주문 서비스를 호출하게 되면 정상적으로 수행된 것을 확인할 수 있습니다.

 

Grafana 로그

반응형

'SpringBoot Monitoring > SpringBoot Resilience4j' 카테고리의 다른 글

RateLimiter 예제  (0) 2021.08.22
Bulkhead 예제  (0) 2021.08.15
CircuitBreaker 예제  (0) 2021.07.31
CircuitBreaker 개념  (0) 2021.07.31