Pythonの優雅な再試行

2608 ワード

符号化では、ネットワーク接続に関連するいくつかのコードフラグメントが再試行されることがしばしばあり、優雅なretry装飾器およびtenacityライブラリの使用を一歩一歩実現する方法について説明した.
オリジナルバージョンv0.0次のような関数形式がある場合、関数にはネットワーク接続を確立する論理があります.
def f():
    # do some connections
    return 0

偶発的なネットワーク接続の失敗を避けるためには、再試行メカニズムを加える必要があります.最も簡単な形式は、対応するコードフラグメントにループを追加することです.ループ体に異常キャプチャを使用し、接続に成功したときにループを終了します.そうしないと、関連論理を繰り返し実行します.この場合、修正された関数fは次のようになります.
def f():
    while 1:
        try:
            # do some connections
            break
        except ConnectionError:
            continue
    return 0

装飾品バージョンv1.0アクセサリーを使用してコードを抽象化できます.例えば、現在2つの関数f1f2が再試行機構を加えて、retryという装飾器関数を書き、f1f2を装飾すればよい.これにより,古いコードの修正が回避され,コード多重化も実現される.例は次のとおりです.
def retry(f):
    def wrap(*args, **kwargs):
        while 1:
            try:
                return f(*args, **kwargs)
            except ConnectionError:
                continue
    return wrap

@retry()
def f1():
    # do some connections
    return 0

@retry()
def f2():
    # do some other connections
    return 0

パラメータ付き装飾品バージョンv1.1v1.0のバージョンretryの装飾器にはいくつかの問題があります.もしある関数が3回再試行したい場合、ある関数が5回再試行したい場合、再試行の間隔も関数によって異なり、v1.0は実現できません.この場合、パラメータ付きの3層装飾器、例えば以下のコードで実現できるretry装飾器を用いて、timesintervalの2つのパラメータを入力して再試行回数と再試行間隔を設定することができる
def retry(times, interval):
    def decorator(f)
        def wrap(*args, **kwargs):
            while times:
                try:
                    return f(*args, **kwargs)
                except ConnectionError:
                    times -= 1
                    time.sleep(interval)
                    continue
        return wrap
    return decorator

#   3     10 
@retry(times=3, interval=10)
def f1():
    # do some connections
    return 0

#   5     15 
@retry(times=5, interval=15)
def f2():
    # do some other connections
    return 0

アクセラレータがパラメータをサポートした後、必要に応じてより豊富なパラメータを定義することができます.たとえば、パラメータによってどの異常をキャプチャする必要があるかなどを設定します.tenacityリリースtenacityはサードパーティのオープンソースライブラリで、関数の再試行に使用されています.実際には、その機能は原理と同じです.ただ定義可能なパラメータはもっと豊富で、車輪を繰り返したくなければ、直接使えばいいです.コードの例は次のとおりです.
from tenacity import retry, stop_after_attempt, wait_fixed

#          
@retry
def f():
    # do some connections
    return 0

#   5     15 
@retry(stop=stop_after_attempt(5), wait=wait_fixed(15))
def f():
    # do some connections
    return 0