API実行のリトライ処理をPythonで実装する方法をまとめます。
なぜリトライ処理が必要か
APIを利用してデータを取得・送信する際には、ネットワーク遅延やサーバーの一時的な負荷などによりエラーが発生することがあります。
例えば、HTTPステータスコード「429 (Too Many Requests)」「500 (Internal Server Error)」「503 (Service Unavailable)」などが返されることがあり、これらは一度のリクエスト失敗だけで処理を諦めるのではなく、時間を置いて再度リクエストすることで成功する可能性があるため、リトライ処理が役立ちます。
リトライ処理の基本的な方法
Pythonでは、以下の2つの方法でリトライ処理を実装することが多いです。
- 手動でリトライロジックを組む
- 外部ライブラリ
retry
やtenacity
を使用する
手動でリトライロジックを組む
以下は、単純に指定回数分リトライするコード例です。
import requests
import time
def fetch_data_with_retry(url, retries=3, delay=2):
for attempt in range(retries):
try:
response = requests.get(url)
# ステータスコードが200番台の場合は成功とみなす
if response.status_code == 200:
return response.json()
else:
print(f"Attempt {attempt + 1}: Failed with status {response.status_code}")
except requests.RequestException as e:
print(f"Attempt {attempt + 1}: Error - {e}")
time.sleep(delay) # リトライ間隔
raise Exception("Failed to fetch data after multiple retries")
上記のコードでは、指定されたリトライ回数だけリクエストを再試行し、成功するまで待機時間(delay
)を設けています。
リクエストが成功しなければ、最後に例外が発生します。
tenacity
ライブラリでリトライ処理を行う
Pythonのtenacity
ライブラリを使用すると、リトライロジックを簡潔に記述できます。
まずはインストールが必要です。
pip install tenacity
次に、リトライ処理を含む関数の実装例を紹介します。
from tenacity import retry, stop_after_attempt, wait_fixed
import requests
@retry(stop=stop_after_attempt(3), wait=wait_fixed(2))
def fetch_data(url):
response = requests.get(url)
response.raise_for_status() # ステータスコードが200以外の場合、例外が発生
return response.json()
try:
data = fetch_data("https://api.example.com/data")
except requests.RequestException as e:
print(f"Failed to fetch data: {e}")
@retry
デコレーターにより、fetch_data
関数は最大3回まで試行し、2秒の待機時間を挟んでリトライします。
このように、tenacity
を使うとリトライ処理の設定が柔軟に行えます。
エラーハンドリングと条件付きリトライ
場合によっては、特定のエラーコードのときだけリトライしたいこともあります。
例えば、ステータスコードが「500」「503」「429」などの場合にリトライするよう条件を設定することが可能です。
条件付きリトライの例
from tenacity import retry, stop_after_attempt, wait_fixed, retry_if_exception
def retry_if_server_error(exception):
return isinstance(exception, requests.RequestException) and exception.response.status_code in [500, 503, 429]
@retry(stop=stop_after_attempt(5), wait=wait_fixed(2), retry=retry_if_exception(retry_if_server_error))
def fetch_data(url):
response = requests.get(url)
response.raise_for_status()
return response.json()
ここでは、リトライ条件としてHTTPステータスが500、503、または429のときのみリトライを行う設定をしています。
エクスポネンシャルバックオフを用いたリトライ処理
エクスポネンシャルバックオフは、リトライ間隔を指数関数的に増加させる手法です。
たとえば、最初のリトライ後に2秒待機、次に4秒、8秒、と待機時間を増やすことで、過剰なリクエストを抑制しつつ成功確率を高めます。
エクスポネンシャルバックオフの例
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(stop=stop_after_attempt(5), wait=wait_exponential(multiplier=1, min=2, max=10))
def fetch_data(url):
response = requests.get(url)
response.raise_for_status()
return response.json()
ここでは、wait_exponential
を使用し、2秒から最大10秒までの待機時間でエクスポネンシャルバックオフを設定しています。
リトライ処理の実装時の注意点
- リトライ回数の上限を設ける
無限ループに陥らないように、リトライ回数に上限を設けます。 - APIプロバイダのガイドラインを確認する
過剰なリトライはサーバーへの負荷が大きいため、APIプロバイダが推奨するリトライポリシーに従うことが重要です。 - エクスポネンシャルバックオフの利用
通常の一定時間リトライよりも、エクスポネンシャルバックオフを利用することで、短時間に集中するリクエストを避けられます。
まとめ
Pythonでは、リトライ処理を手動で実装する方法や、tenacity
ライブラリを用いる方法があり、リトライの条件や待機時間も自由に調整可能です。これらの手法を活用することで、APIの実行における堅牢性を向上させ、安定したデータ取得が可能になります。