LoginSignup
0
1

More than 1 year has passed since last update.

pythonのbackoff

Posted at

@backoff関連情報がないのでここにメモします。

pythonでbackoffは特定なエラーが発生するとそれをバックオップさせ、リトライをするデコレーターです。

まずpipインストールをします。

$ pip install backoff
Collecting backoff
  Downloading backoff-1.11.1-py2.py3-none-any.whl (13 kB)
Installing collected packages: backoff
Successfully installed backoff-1.11.1

簡単な例えを見ましょう。

def test():
    number = int(input("Enter an integer: "))

test()

このコードを実行しintではない値を与えたらValueErrorが発生しますが、入力の誤りを三回くらいは勘弁しようと思います。方法は二つです。

  • input(...)の結果をタイプをチェックしてintであればPass, そうじゃなければindicator変数を指定してこの変数が3を超えたらVauleErrorを発生させる。
  • @backoffを使用する。

一番目はコードの修正範囲が広いので複雑になります。だから二番目を使用します。

import backoff

@backoff.on_exception(backoff.expo,
                      ValueError,
                      max_tries=3)
def test():
    number = int(input("Enter an integer: "))

test()

実行結果です。

$ python3 3test.py
Enter an integer: e
Enter an integer: r
Enter an integer: t
Traceback (most recent call last):
  File "3test.py", line 9, in <module>
    test()
  File "/home/ubuntu/.local/lib/python3.8/site-packages/backoff/_sync.py", line 94, in retry
    ret = target(*args, **kwargs)
  File "3test.py", line 7, in test
    number = int(input("Enter an integer: "))
ValueError: invalid literal for int() with base 10: 't'

@backoffデコレーターでmax_tries=3を設定するとリトライを三回してもう一度誤りの値が与えられたらVauleErrorを発生させます。

これが有用な場合はAPIサーバーとかDBのような異なるサーバーで接続する時です。次のコードはDB接続+HTTP request接続をするコードの一部の抜粋です(from the book “Robust Python”)。

import backoff
import requests
from autokitchen.database import OperationException 
# setting properties of self.*_db objects will
# update data in the database

@backoff.on_exception(backoff.expo,
                      OperationException,
                      max_tries=5) 
def on_dish_ordered(dish: Dish):
    self.dish_db[dish].count += 1

@backoff.on_exception(backoff.expo,
                      OperationException,
                      max_tries=5) 
@backoff.on_exception(backoff.expo,
                      requests.exceptions.HTTPError,
                      max_time=60)
def save_inventory_counts(inventory):
    for ingredient in inventory: 
        self.inventory_db[ingredient.name] = ingredient.count

一番目の関数on_dish_ordered@backoffはDBの接続がOperationExceptionで失敗すれば最大5回までリトライさせます。

二番目の関数save_inventory_counts@backoffを重ねて使用してます。save_inventory_countsがDBとHTTP.request両方を使っているので一番目の@backoffはDBのOperationException発生際5回まで、二番目の@backoffではHTTPError発生際60秒(max_time=60)までリトライさせます。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1