에러기록
api 재호출을 위한 while 문을 Spring @Retryable 을 통해 리팩토링 하기
개미는뚠뚠
2024. 5. 15. 18:17
1) 문제 상황
회사에서 진행하던 파이썬 프로젝트를 spring boot 로 포팅하는 일을 맡아서 진행 중이다. 진행하면서 코드 리팩토링도 같이 진행하기로 했는데 외부 api를 호출하는 기존의 코드가 api를 호출 하기위해(?) 한 function에 while문을 3번이나 호출하고 있었다.
기존 코드의 흐름은 다음과 같다.
cuntValue = 0;
whlie(true){
// api 호출 코드
// header에서 api 호출이 40번이상이거나 cuntValue가 5이상이면 break;
if( ){
break;
}
}
▲기존 코드 예시 .. .이런 무한 루프가 3개나 있었고 여러 함수들이 다 이렇게 되어있었다 🥹
위와 같은 코드가 한 function에 3번이나 호출 되고 있었고 무한루프를 마구잡이로 사용하는 건 서버에 과한 부담을 줄 수 있다고 판단해 해당 코드를 리팩토링하기로 했다.
2) 문제원인
기존 코드 분석
- 기존의 코드는 api 요청에서 에러가 발생해도 response 데이터를 받아올때까지 api를 호출 하기위해 작성된 코드였다.그렇다보니 무한 루프를 통해서 api요청을 하고있었고 중간에 너무 많은 요청으로 인해 api call 요청을 거절 당하기도 했다.
- 이를 막기 위해 try catch 코드로 에러가 나도 무시하고 계속 재 호출을 하도록 처리 되고있었다.
- 반복되는 무한 루프 코드로 인해 코드의 가독성을 해치고 있었고 무한 루프문은 서버에 과한 부담을 줄 염려가 있었다.
리팩토링 방향
- 3개나 되는 무한 루프를 제거하고 api의 reponse 값에 따라 api를 재호출하는 코드로 변경
- API를 호출하는 부분을 utils로 따로 빼서 다른 service단에서도 재활용.
3) 문제해결
Spring @Retryable을 통한 코드 리팩토링
- Spring Retry는 특정한 상황에서 쉽게 재호출을 할 수 있는 라이브러리로 해당 라이브러리를 사용해서 코드를 리팩토링 하기로 했다.
해당 라이브러리 : https://github.com/spring-projects/spring-retry - 라이브러리 설치
implementation 'org.springframework.retry:spring-retry'
implementation 'org.springframework:spring-aspects'
implementation 'org.aspectj:aspectjrt'
implementation 'org.aspectj:aspectjweaver'
implementation 'org.aspectj:aspectjtools'
- 참고로 Retry는 결국 AOP이다. 그렇기때문에 retry말고도 AOP 의존성을 추가해줄 필요가 있다.
- @Retryable 설정
- maxAttempts : 최대 시도 횟수
- backoff : 다음 재호출 시간 대기 시간
- multiplier : 다음 재 호출시 현재 대기 시간의 배수
- delay : 재 호출 전 대기 시간
- value : value 설정을 통해 특정 exception에서만 재호출 하도록 설정 할 수 있음.
@Retryable( maxAttempts = 5 , backoff = @Backoff(10000))
// api 호출코드
}
▲ 리팩토링한 코드 예시
결과
- 불필요한 무한 루프 제거
- 어노테이션을 사용해 자동화
- 약 20줄(*3번)에 달하던 코드를 8줄로 줄여 모듈화하고 해당 코드를 함수안에서 호출 함으로써 1줄의 코드로 함수의 전체적인 복잡도를 떨어뜨리고 가독성을 높이는 코드로 리팩토링했다.👏👏👏👏
- 처음 코드를 봤을때만 해도 어마무시한 복잡도와 파이썬 -> spring으로 포팅한다는 점 때문에 고민과 걱정이 많았지만 무사히 리팩토링과 해당 기능의 포팅을 진행 할 수 있었다는 점에서 기록으로 남긴다!