
t0mmy
学習履歴詳細
APIデザインパターン 10章 ロングランオペレーション 読了
やったこと
- APIデザインパターン 10章 ロングランオペレーション 読了
学んだこと
ポイント
- LROとは
- どういった問題を解決できるか
- LROによる非同期APIの実装に必要なもの
- LROにメタデータ
- LROを取り扱う二種類の方法
学び
- LROはAPIで非同期処理を実現するための仕組み
- javascript の
Promise
や python のFutures
のようなもの
- javascript の
- HTTPのリクエスト/レスポンスとは異なる点(≒気を付けるべき点)が多々ある
- Operationリソース、LROを管理するAPIの設置、メタデータを持たせるなど
- LROの取り扱いには 「ポーリング」と「待機」という選択肢がある
- LROのキャンセル/一時停止/再開は必須ではない
- 提供することに価値があれば、実装する
- LROは保持期間を設けると良い
気づき
- LRO
- クライアント側が楽になる(同期処理)と、APIが辛くなる(待機)
- API側が楽になる(非同期処理)と、クライアント側が辛くなる(ポーリング)
- これは、クライアント側とAPI側のトレードオフなのかもしれない
メモ
取り扱う問題
APIで、時間がかかる処理を扱いたい。
- 言い換えると、直ぐにレスポンスを返すことが出来ないような処理
そして、API設計において、レスポンスが早い処理と、レスポンスが遅い処理の両方に一貫性を持たせることは難しい。
概要
API で、時間がかかる処理を扱いたい。
そのために、非同期処理の仕組みを構築する。
非同期処理の仕組みとして、Javascript の Promise
や、Python の Futures
に相当する仕組みをWeb APIに実装する。
本書では、 この仕組みを LRO (Long-running Operation)と呼ぶ。
LRO は、 Javascript の Promise
や、Python の Futures
と比較して、以下の点が異なる
- LRO生成後、一リソースとして残り続ける
Promise
は処理完了後破棄される
- LROは、オペレーションの進捗状況を含むメタデータを含む
- 呼び出し側は、メタデータから、オペレーションの進捗を確認できる
実装
LROによる非同期APIを実装するために、以下の二つが必要。
- Operation リソースとして、以下の二つを定義する
- 処理完了後に返却されるリソースの型
- LROのメタデータ
- APIでLROを発見し、管理する方法を提供する
- LROは、作成された場所とは異なる環境に存在することがほとんどのため、検索が必要
- 取得には、
get
やlist
といった標準メソッド - 管理には、LROの「一時停止」「再開」「キャンセル」を要求できるカスタムメソッド
LROには、以下を持たせる。
- 処理の成功/失敗を表現する
result
フィールド - 処理が完了したかどうかを示すフラグ
- 処理の進捗を含むメタデータ
LRO リソースの保存場所
LROは非同期処理を管理するオブジェクトであり、どこかで管理する必要がある。
管理場所として最もよいのは、Operation
リソースのトップレベルコレクション。
/operations/1
、operations/2
など
LROの取り扱い
受け取った LRO を解決する。
◇ポーリング
"処理が完了したかどうかを示すフラグ" が完了状態になるまでポーリングする。
計算時間の無駄が発生するが、理解しやすく、クライアント側にも責任を負わせることが出来る。
- 最大遅延時間と、無駄な時間やリソース消費のトレードオフ
- ポーリング間隔を長くすると、リソース消費は抑えられるが、結果を得るまで時間がかかる
- ポーリング間隔を短くすると、結果を得るまでの時間を短縮できるが、リソース消費が膨れ上がる
◇待機
クライアント側は、APIサービスとの接続を切らずに(≒セッションを確立したまま)待機する。
API側は、処理完了後にレスポンスを返す。
- 言い換えると、、処理が完了するまでクライアントへのレスポンスを行わない
クライアント側のポーリング処理が不要となり、処理が単純になる(関数の同期呼び出しと、感覚は同じ)。
反面、API側は接続の管理、確実にレスポンスを返す(≒レスポンスに責任を持つ)
実装には、 wait
カスタムメソッドを用いることになる。
/{id}/:wait
エラー処理
LROのエラー処理にHTTPのエラーコードを用いると、HTTPのエラーか、RLO処理に伴うエラーなのか判別が困難になる。
そのため、エラーを伝える別の手段が必要。
別の手段として、処理の成功/失敗を表現するresult
フィールドでエラーを表現する。
進捗のモニタリング
RLOのメタデータを使用して、クライアント側に進捗状況を示すデータを渡す。
格納するデータは、実装側で任意に決めることが出来る。
- 例) タイムスタンプ、完了までの残り推定時間、総バイト数と処理したバイト数 ... など
- クライアントにとって価値あるデータを渡そう!
オペレーションをキャンセルする
CancelOperation
カスタムメソッドを実装して、クライアントが処理のキャンセルをリクエスト出来るようにする。
LROの完全な停止を確認してから、クライアントに、キャンセル完了を返す。
キャンセル処理は、ポーリング(非同期)よりも、待機(同期)の方が良い。
キャンセル処理の目的は、「リクエスト自体がなかった」状態へ戻すこと。
そのため、LROによって生じた中間ファイルの削除(いわゆるクリーンアップ)も忘れないこと。
キャンセル機能の実装は任意。
クライアントにとって、キャンセル処理に価値があれば、実装すると良い。
LROの一時停止と再開
一時停止/再開も、カスタムメソッドを実装することで、クライアントがリクエスト出来るようにする。
一時停止リクエストは、一時停止に成功した旨をクライアントに伝える必要がある。
一時停止/再開といった状態を示すメタデータを持つと良い (paused:boolean
など )。
キャンセル機能同様、一時停止/再開機能の実装は任意。
クライアントにとって、キャンセル処理に価値があれば、実装すると良い。
オペレーションを検索する
APIを処理する環境と、LROを実行する環境は分離することが多い。(AWS LambdaとAWS Batchに分離する...など)
LROのクラッシュなどを追跡できるよう、別環境で実行したLROを管理・検索できる必要がある。
この問題は、Operationのコレクションを返却する、list
標準メソッドを実装することで解決できる。
このとき、「一時停止しているLRO」など、何らかのフィルタリング手段も併せて実装する。
LROの永続性
LROは、APIが生成する永続性のあるリソースとは異なる。
処理状況をを管理するために、扱いリソースで表現したものがLRO、というイメージ。
リソースの有効期限は、LROの最終的な結果の種類に依存してはならない。
永続性の選択肢にはいくつかある。
- 他のリソース同様、永続化する
- 有効期限を設け、有効期限が切れたLROを削除する
- 更に複雑なロジックで管理する
- 時間経過で段階的にアーカイブする、LROに結びつくリソースの削除に合わせてLROも削除する、など
- ロジックの実装・運用コストが発生するため非推奨
扱うこと
- 非同期APIでロングランオペレーションを使用する方法
- オペレーションの進捗に関するメタデータを保持する
- オペレーションはリソース階層のどこに配置するべきか?
- ポーリングとブロッキングによるオペレーションの状態(エラーを含む)の確認
- 実行中のオペレーションの操作(一時停止、再開、キャンセルなど)
まとめ
- LROは、Web API版の Promise や Futures で、 APIサービスがバックグラウンドで行っている作業をトラッキングするツールとして機能する
- LROはパラメータを持つI/Fで、具体的な結果と、LRO自身の進捗情報を保存するためのメタデータタイプを返却する
- LROは一定時間後に結果またはエラーを返す
- 利用者は、以下のどちらかの方法で、レスポンスの有無を知ることができる
- 定期的に状態をポーリング
- 待機中に結果が通知される
- 利用者は、以下のどちらかの方法で、レスポンスの有無を知ることができる
- LROは、APIの判断で「一時停止」「再開」「キャンセル」可能
- なお、これらはカスタムメソッドで実施する
- LROは、理想は永久保存するべき
- 一般的には、標準的な時間(30日など)が経過したものは破棄する
2023年06月15日(木)
1.5時間