ジャコ Lab

プログラミング関連のメモ帳的ブログです

Python でリトライするデコレーター

リトライ処理をデコレーターにまとめたかったので作りました

デコレーターとは?

度々、Python のメソッドの前に付いている @xxx の部分のことです。 ChatGPT に「そもそもデコレーターとは?」を聞いてみました

質問
Python におけるデコレーターってなんですか?
ChatGPT の回答
デコレーターは、Python の関数やメソッド、クラスに です。簡単に言えば、「ある関数やクラスを他の関数でラップして、動作を拡張する仕組み」です。
メソッドをラップできる機能ということですね。今回は特定のメソッドをラップしてリトライ機能を追加するという感じですね

デコレーター

[retry_decorator.py]

import functools
import time

def retry_on_exception(*, max_attempts: int = 1):
    """Retry decorator."""
    def decorator(func: callable):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(max_attempts):
                try:
                    print(f'Calling (Attempt: {attempt + 1})')
                    return func(*args, **kwargs)
                except Exception as ex:
                    last_exception = ex
                    print(f'Failed on (Attempt: {attempt + 1})')
                    if attempt < max_attempts - 1:
                        delay = 2 ** attempt
                        time.sleep(delay)
                        continue
            raise last_exception
        return wrapper
    return decorator
リトライ処理のアプローチは エクスポネンシャルバックオフ です

実行コード

[run.py]

from retry_decorator import retry_on_exception

@retry_on_exception(max_attempts=3)
def unstable_function():
    """意図的に例外を発生させる関数。"""
    raise ValueError("Intentional error for testing.")

@retry_on_exception(max_attempts=3)
def stable_function():
    """一度で成功する関数。"""
    return "Success"

if __name__ == '__main__': 
    print("===== stable_function() =====")
    res = stable_function()
    assert res == 'Success'

    print("===== unstable_function() =====")
    try:
        unstable_function()
    except ValueError as ex:
        print(ex)

実行ログ

$ python run.py 
===== stable_function() =====
Calling (Attempt: 1)
===== unstable_function() =====
Calling (Attempt: 1)
Failed on (Attempt: 1)
Calling (Attempt: 2)
Failed on (Attempt: 2)
Calling (Attempt: 3)
Failed on (Attempt: 3)
Intentional error for testing.

まとめ

なんかいい感じに動いたので嬉しい。毎回、各メソッドにリトライ処理書いてたのでこれから楽できる・・・。それよりも久々に VSCodePython ファイルを開いたんだけど、全く推論や補完してくれなくなってる・・・