t0mmy

2020年12月30日に参加

学習履歴詳細

APIデザインパターン 10章 ロングランオペレーション 読了

やったこと

  • APIデザインパターン 10章 ロングランオペレーション 読了

学んだこと

ポイント

  • LROとは
    • どういった問題を解決できるか
  • LROによる非同期APIの実装に必要なもの
  • LROにメタデータ
  • LROを取り扱う二種類の方法

学び

  • LROはAPIで非同期処理を実現するための仕組み
    • javascript の Promise や python の Futuresのようなもの
  • 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は、作成された場所とは異なる環境に存在することがほとんどのため、検索が必要
    • 取得には、 getlist といった標準メソッド
    • 管理には、LROの「一時停止」「再開」「キャンセル」を要求できるカスタムメソッド

LROには、以下を持たせる。

  • 処理の成功/失敗を表現するresult フィールド
  • 処理が完了したかどうかを示すフラグ
  • 処理の進捗を含むメタデータ

LRO リソースの保存場所

LROは非同期処理を管理するオブジェクトであり、どこかで管理する必要がある。
管理場所として最もよいのは、Operationリソースのトップレベルコレクション。

  • /operations/1operations/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日など)が経過したものは破棄する
WebAPI

2023年06月15日(木)

1.5時間