はじめに
外部サービスを呼び出しをする時に、リトライについて考慮した方がいいとわかったことをメモしておきたい。(呼び出すサービスにもよると思うし、判断材料については他にもあるのだろうと思うが、今回関係したものをメモしておく。)
外部サービスと言っているのは、AWSのS3・lambdaや、外部のAPIのことを指している。
失敗したらリトライするべきか
判断材料(例)
-
リトライしたら成功する可能性があるのか
- エラーの場合に一律リトライするのではなく、リトライで成功する可能性があるエラーだけ選んでリトライするのがよいよう。
- ステータスコードを元に判断するのがよい。リトライして成功する可能性があるのは、たとえば 503(Service Unavailable)や 504(Gateway Timeout)、429(Too Many Requests)など。一方で、400(Bad Request)や403などのリクエストに問題があるエラーは、リトライしても成功しない場合が多い。
-
リトライした時の待ち時間がどれくらいになるか
- あまりにも長いようであれば失敗にしてユーザーにリトライしてもらった方がストレスが少ない?など。個人的には失敗になるよりは待ち時間が長い方がストレスが少ないようには思うが。
- リトライすることでサービスのタイムアウトを超えないかなども確認が必要。
すぐリトライするか少し待ってからリトライするか
判断材料(例)
- 失敗の原因
- 高負荷によるものなら少し待ってからリトライした方がいいかも
- 負荷とは関係なくランダムに失敗があり、できるだけ早くレスポンスを返したい時は待たない方がよいのだろうか?
AWS SDKのように、ライブラリでリトライ設定とどれくらい待ってからリトライするかを設定できることもあるよう。例えばAWS SDK for Javaでは、デフォルトで3度リトライが行われる。
ライブラリを見ていると、リトライごとに少しずつ待ち時間を長くしていくのが多いよう。
memo: ジッター:ランダム値を乗じてリトライ処理によるアクセスを分散させるときのランダム値
何回リトライするか
ここは決めの問題かもしれない。
判断材料(例)
- リトライした時のレスポンスタイム
- リトライした時の負荷
リトライ先・リトライ条件
もし接続先(リージョンなど)を変えても問題ない場合、変えるという選択肢もある。
判断材料(例)
- エラーの原因
- リージョン単位でサービスが不安定になることがある、などならリージョンを変えてみるのもあり
- 高負荷
- 負荷が高いなら別の接続先に接続してみるのもあり
- コスト
- 接続先を変えることでコストがあがるのか
- 運用
- 接続先を変えることで動作や運用は変わらないのか(例えばS3とかだと保存先が変わってしまうのでダメだと思う。APIなど結果を受け取るだけのものなら問題ないかもしれない。)
おまけ
- 同じ案件で、ログの仕込み方も勉強になり、以下にメモしています。
-
外部サービス呼び出しに長い時間がかかるなら、そこはトランザクションからはずした方がよい。(今まで担当してきたシステムだと、基本Serviceクラスにトランザクションを貼ることが多かったが、Serviceから外部サービス呼び出しとDB書き込みを両方呼び出している場合、長いトランザクションになってしまうことがあった。トランザクションが長くなってしまうとDBのロック時間が長くなり、デッドロックやDBの性能劣化を招くことがある。)
-
Retry-Afterヘッダーと呼ばれる、「何秒後にリトライしてほしいか」がレスポンスヘッダーに含まれることもあるらしい(使ったことはない)。