나는 이렇게 학습한다/Library

Tenacity _ 예외가 발생한 함수를 다시 실행하려면?

daco2020 2022. 8. 27. 18:09
반응형

Tenacity 란?

보통 에러나 예외처리에 의해 런타임이 종료될 때가 있다. Tenacity는 런타임 종료없이 함수를 다시 실행시켜주는 Python 라이브러리이다.

 

 

 

 

사용법

1. Tenacity 설치

pip install tenacity

 

 

 

2. Tenacity 라이브러리 가져오기 및 함수 작성

import tenacity

def throw_error():
    print("running...")
    raise ValueError("Errors make me stronger")

if __name__ == "__main__":
    throw_error()

 

 

 

이대로 스크립트를 실행해보면 우리가 의도한대로 에러가 발생하며 곧바로 스크립트가 종료된다.

running...
Traceback (most recent call last):
...
ValueError: Errors make me stronger

 

 

 

3. 재실행 횟수 지정하기

@tenacity.retry( # 데코레이터 추가
    stop=tenacity.stop_after_attempt(5), # stop 파라미터 추가
)
def throw_error():
    print("running...")
    raise ValueError("Errors make me stronger")

@tenacity.retry 데코레이터를 추가했다. stop 파라미터에는 재실행을 언제 멈출지에 대한 인자를 넣는다. stop 파라미터에 tenacity.stop_after_attempt를 불러와 5를 넣어보자. 여기서 5는 재실행 횟수를 의미한다.

 

 

 

다시 스크립트를 실행해보면 아래처럼 함수가 5번 실행되고 에러를 반환한다. (만약 5번 이내 에러가 발생하지 않는다면 스크립트는 종료되지 않고 다음 코드를 읽을 것이다)

running... # 1번
running... # 2번
running... # 3번
running... # 4번
running... # 5번
Traceback (most recent call last):
...
tenacity.RetryError: RetryError[<Future at 0x1050b6370 state=finished raised ValueError>]

 

 

 

4. 실행 간격 지정하기

@tenacity.retry(
    wait=tenacity.wait_fixed(10), # wait 파라미터 추가
    stop=tenacity.stop_after_attempt(5),
)
def throw_error():
    date = datetime.datetime.now().time() # 시간을 확인하기위해 추가
    print(f"time: {date}, running... ")
    raise ValueError("Errors make me stronger")

wait 파라미터에 tenacity.wait_fixed(10)을 지정해주었다. 여기서 10은 10초를 의미한다.

 

 

 

스크립트를 실행해보면 이번에는 10초 간격으로 5번 실행된다.

time: 13:29:27.350657, running... 
time: 13:29:37.355707, running... 
time: 13:29:47.358180, running... 
time: 13:29:57.368775, running... 
time: 13:30:07.371236, running... 
Traceback (most recent call last):
...
tenacity.RetryError: RetryError[<Future at 0x1054425e0 state=finished raised ValueError>]

이제 우리는 재실행 횟수와 간격까지 지정할 수 있다.

 

 

 

5. 지정한 에러 메시지 띄우기

그런데 tenacity.RetryError 라는 메시지는 우리가 원한 것이 아니다. 우리가 지정한 ValueError가 보일 수 있도록 reraise 옵션을 추가하자!

@tenacity.retry(
    wait=tenacity.wait_fixed(10), 
    stop=tenacity.stop_after_attempt(5),
    reraise=True, # reraise 파라미터 추가
)
def throw_error():
    date = datetime.datetime.now().time()
    print(f"time: {date}, running... ")
    raise ValueError("Errors make me stronger")

 

 

 

우리가 지정한 ValueError: Errors make me stronger 가 정상적으로 나오는 것을 볼 수 있다.

time: 13:33:00.953681, running... 
time: 13:33:10.958907, running... 
time: 13:33:20.960167, running... 
time: 13:33:30.970997, running... 
time: 13:33:40.976130, running... 
Traceback (most recent call last):
...
ValueError: Errors make me stronger

 

 

 

언제 사용하는가?

그렇다면 Tenacity는 언제 사용하는 걸까?

 

 

만약 특정 API 호출 시 종종 실패 응답이 온다고 가정해보자. 그리고 그 실패 때문에 에러가 발생하고 런타임이 종료된다면..?

 

우리는 정상 응답을 받기 위해 해당 스크립트를 수동으로 다시 실행해야한다. 또는 스케줄러를 이용하여 특정 시간에 재실행하도록 설정할수도 있다. 하지만 이러한 방법들은 번거롭고 즉각 반응하기 어렵다는 단점이 있다.

 

 

바로 이런 경우에 Tenacity 라이브러리를 사용하면 문제를 해결할 수 있다. 에러 발생 시 특정 간격 이후로 재실행을 유도할 수 있고, 그 중요도에 따라 횟수도 지정할 수 있다. 만약 그럼에도 실패한다면 최종적으로 에러메시지를 띄워 관리자에게 알려줄 수 있다.

 

 

위와 유사한 문제를 겪고 있는 분들이 있다면 Tenacity 를 사용해보길 권한다.

 

 

 

 

 

Tenacity에 대해 더 자세히 알고 싶다면 아래 공식문서를 참고하라.

 

Tenacity — Tenacity documentation

Tenacity Tenacity is an Apache 2.0 licensed general-purpose retrying library, written in Python, to simplify the task of adding retry behavior to just about anything. It originates from a fork of retrying which is sadly no longer maintained. Tenacity isn

tenacity.readthedocs.io

 

 

 

반응형