リトライ処理を自分で作り込まずに、backoffモジュールを活用することでよりコードがシンプルになる。
これからはbackoffモジュールを活用していきたい。
backoffモジュールとは
backoffモジュールは条件が満たされるまでリトライするためのデコレータ。
ネットワークリソースやAPI、信頼性が低く、障害が発生する可能性のあるリソースにアクセスする際、使用することを目的としている。
使い方
backoff.on_exception
デコレータにリトライする対象のExceptionクラスを定義。
第一パラメータのbackoff.expo
はひとまずおまじないと思っていればいい。
下記の例だと、Exceptionが発生し続ければ、ずっとリトライする。
import requests import backoff @backoff.on_exception(backoff.expo, Exception) def handler(): print("Start handler") try: response = requests.get("http://localhost:8081") except Exception as e: print("occur Exception") raise e print("End handler") if __name__ == '__main__': handler()
リトライの設定
max_tries
パラメータは、実行回数を設定する。
例えば、実行失敗時に、2回までリトライをさせる場合、最初の実行も回数に含めて3を設定する。
import requests import backoff import time @backoff.on_exception(backoff.expo, requests.exceptions.RequestException, max_tries=5, jitter=None) def handler(): print("Start handler") try: start = time.time() response = requests.get("http://localhost:8000", timeout=(5.0, 5.0)) except Exception as e: end = time.time() print("occur Exception") print("Execute time = " + str(end - start)) print(e) raise e end = time.time() print("End handler time = " + str(end - start)) if __name__ == '__main__': handler()
再実行時のリトライ間隔の設定
再実行時のリトライ間隔は、設定するWatiGeneratorで決まる。
backoff.expo
を指定した場合、指数関数で増加する。デフォルトの場合、2のX乗。
backoff.fibo
を指定した場合、フィボナッチ数列で増加する。
backoff.constant
を指定した場合、リトライ間隔は一定となる。デフォルトは1秒。
backoff.constant
のリトライの間隔を変更したい場合、interval
パラメータを指定する。
リトライの間隔を5秒に変更したい場合は、interval=5
を指定する。
@backoff.on_exception(backoff.constant, Exception, jitter=None, interval=5
リトライ間隔を1秒、10秒、20秒のようにカスタマイズしたい場合、interval
パラメータにリストで間隔を設定する。
@backoff.on_exception(backoff.constant, Exception, jitter=None, interval=[1, 10, 20]
リトライ時のばらつきを含める
backoff
モジュールにはリトライ時のタイミングにばらつきを持たせるために、jitterパラメータが用意されている。
複数のユーザが操作によるリトライが発生した場合、リトライによる際実行が同じになり、多くのリクエストが発生する。
そのため、jitterによる時間のずれを含めることで、リトライのタイミングをずらして再実行によるリクエストの増加を防ぐ。
実行のタイミングのずれを含めたくない場合、jitter=None
の指定が必要になる。
https://aws.typepad.com/sajp/2015/03/backoff.html
最後に
backoffモジュールを使うことで簡単にリトライをするための実装が可能となる。
ほかにもon_predicate
を使用して、ポーリングも続けることができる。
また、複数のデコレータを指定することもの可能だ。
backoffモジュールを使い倒すことで、リトライ系のことは何でもできそうな気がする。
これからは自分でリトライ処理は作り込まず、backoffモジュールを活用していきたい。