私のチームと私はサードパーティ企業と統合し、それらのAPIを使用してさまざまなCRUD操作を実行しています。ただし、APIは常に信頼できるとは限りません。たぶん、0.1%の確率でAPI呼び出しは500エラーで失敗し、その後再試行すると正常に動作します。ときどき、API呼び出しが時間の90%以上の500エラーで失敗する場合があります。約10回の試行後、最終的には機能します。通常、約4時間続き、数か月ごとに発生します。私たちは昨日、API呼び出しが失敗する時間の90%を経験しました。
サードパーティから、500エラーを受け取った場合は再試行ロジックを実装する必要があると言われました。べき等演算の場合、これが役立つことがわかりました。ただし、非べき等操作の場合は危険である可能性があります。たとえば、1つのAPI呼び出しでメールを送信する場合があります。メールが送信されていても、APIが500エラーを返す場合があることに気づきました。 API呼び出しを10回再試行すると、10 500のエラーが発生する可能性がありますが、受信者は引き続き10のメールを受信する可能性があります。これは非常に悪い可能性があります。
べき等ではない500エラーに対して再試行ロジックを実際に追加する必要がありますか?
いつ再試行を追加するかについての2つの考え:
500エラーの取得は非常にスリムなので、API呼び出しに再試行ロジックを追加する必要はありませんでした。これをしなければならないのは理にかなっていますか?
これは具体的には、特定の非べき等演算でより悪いものに要約されます。
複数回実行されたとき、または
まったく実行されない場合。
これは技術的な設計上の決定ではなく、特定の操作と、ドメイン内のそのような障害の結果によって異なります。
技術的な手段として、特定の操作が(少なくとも特定の確率で)発生したかどうかを検証するための追加のオプションがあるかどうかを確認できます。電子メールの例を見てみましょう。APIでブラインドコピーリクエストが含まれている電子メールリクエストを送信できる場合は、この機能を利用して独自のシステムにブラインドコピーを送信できます。これにより、元のメールが送信されたかどうかにかかわらず、追加のチェックポイントを実装する機会が与えられます。もちろん、ネットワークラグが原因でブラインドコピーが時間内にシステムに到達しない場合がありますが、APIを使用してメール操作の重複の頻度を減らすことができます。
または、API自体によって、特定の操作の特定のステータスまたはログ情報を検査できる場合があります。これらの呼び出しも失敗する可能性がありますが、少なくとも、これらの機能を使用することにより、失敗率を許容できる程度に下げることができる場合があります。
一般的なエンジニアリングの原則として:システムに信頼できないコンポーネントがある場合は、システムを「十分に信頼できる」ものにするために十分な冗長性を作成します。
API呼び出しが「at-least-once」、「at-most-once」、「exactly-once」のいずれであるかを決定します( http://www.cs.unc.edu/~dewan/242/f97 /notes/ipc/node27.html )緊急度の観点から。 at-least-onceの場合、ある種のバックオフ(たとえば、指数バックオフ)を使用して再試行ロジックを記述します。その他の場合は、監視とアラートをより適切に実装して、問題がいつ発生するかを把握します。失敗した操作をキューに移動し、キューから操作を手動で選択して実行できるUIを実装します。
経験則として、はい。 5xxは「サーバーエラー」であり、REST APIの世界では、これはよくあることです。ケースほど頻繁ではありませんが、よくあることです。
例えば。 APIゲートウェイを使用してAWSでホストされているAPIの場合、Java Lambdaは平均して2日に1回500/503/504をスローします。通常、最初の再試行が行われます。問題は一時的なインフラストラクチャの問題であり、ゲートウェイ接続、ランバに到達できない、ネットワークの問題...
ALL REST呼び出しは、5xxエラーの再試行間で指数関数的に増加する遅延で再試行する必要があります。すべてのライブラリで使用可能なライブラリがあります。ループには使用しないでください。
もちろんべき等性は少し複雑になりますが、私は経験則に基づいています。例えば。 503、504は確実に再試行できることを意味します。 APIは、500秒間の動作を保証またはガイダンスする必要があります。
もちろん、私は有料APIが4時間ダウンしてはならないであるという他の意見を裏付けます。
原則として、500エラーを再試行する必要があります。ほとんどのエラーコードには経験則があります。
4xxエラーは通常、本質的に不良で処理できない要求に要約されます。 5xxエラーは、サーバーでプライベートな問題が発生したことを示すために使用され、リクエストが無効である可能性があることを示すものはありません。
それはあなたのリクエストが有効であったに違いないという意味ではありません。たとえば、アイテムを取得するリクエストを送信したが、存在しないIDを使用するとします。要求を適切に処理するサーバーは、404応答(または204を返します。どちらの方法でも議論を聞いたことがあり、その違いは状況に応じたものだと思います)。ただし、サーバーにnull参照例外を引き起こすバグがある場合、500応答が返される可能性があります。
発信者として500応答を受け取った場合、何が問題だったかわかりません。あなたが知っているのは、あなたのリクエストが無意味であることをサーバーが積極的にあなたに伝えなかったことだけです。つまり、同じリクエストを再度実行しても意味がないとは想定できません。
たとえば、サーバーデータベースがオフラインだったために500を受け取った可能性があります。少し待ってから再試行すると、データベースがオンラインになったため、成功する場合があります。
しかし、4xxエラーを受け取ったとき、サーバーはリクエストが解決できないことを積極的に表明しており、再試行しても意味がありません。
これは少し一般化しすぎて、例外的な例外が存在します。たとえば、ステータス429(リクエストが多すぎる)は、あなた(発信者)が割り当てられたコール数を超えたことを意味しますが、さらに多くのリクエストが割り当てられるまで待機すると(たとえば、 1日の最大値に達した場合、明日再び機能します)。
ただし、sul4bhは正しい可能性があり、これはコンテキストに依存する場合があり、一部のアプリケーションでは、同じ要求を複数回送信することを望まない場合があります。
たとえば、銀行取引を考えてみましょう。リクエストを送信し、500を取得します。しかし、実際には、サーバーは実際にリクエストを処理しましたが、応答メッセージのフォーマットにささいなバグが発生しました。
最終的に複数の銀行取引を行うことになるため、もう一度リクエストを送信すると害を及ぼす可能性があります。
ただし、これは、あなた(呼び出し元)が同じ要求をいつ許可するか、いつ許可しないかを決定することだとは思いません。発信者に物事の真の状態を明確に伝えるのはサーバーの責任であり、上記のシナリオではそうすることができませんでした。悪い情報を与えられ、与えられた情報に正しく応答する責任を負うことはできません。
オンラインバンキングで支払いを行い、トランザクションを送信したときに500を受け取った場合は、それを再試行します。これは、500エラーに対する最も意味のある応答です。そのために、私の銀行では実際に小切手を行っています。同じ金額および/または同じ口座で2回目の送金をすばやく続けていることに気付いた場合、最初の取引が実際に登録されたことが通知されます。
したがって、これはサーバーに大きく依存します。彼らはあなたに明確に通信することが期待されており、あなたが明確な通信を想定している場合、500は問題の原因がリクエストではなくサーバーサイドにあったため、後で再試行する必要があることを意味します。
サーバーが明確に通信できない場合、またはアプリケーションのコンテキストで呼び出し側が同じアクションを2回実行しないことを誤る必要がある場合、サーバーの管理者はそれをAPIのコンシューマーに明確に伝える必要があり、誤って同じアクションを2回行うことを防ぐために合理的な努力をします。