ロングランオペレーション
LRO
通常のAPIは、リクエストを受け取るとすぐに何かしらの処理を行い、その結果をすぐに返します。これは、APIがすぐに結果を返すことが期待される「同期的な」動作です。しかし、APIが行う仕事が複雑で時間がかかる場合、すぐに結果を返すことは難しくなります。例えば、大量のデータを処理するなどの重労働が必要な場合や、外部のサービスに接続するなどの作業が必要な場合です。
このような問題は、Web APIだけでなく、ローカルに実行されるプログラムでもよく起きます。時間がかかる処理をしたいけれども、その処理が終わるのを待っている間に他の作業を進めたいという場合です。このような問題を解決するために、最近のプログラミング言語では「非同期動作」を扱うための構文が用意されています。PythonではFutures、JavaScriptではPromisesと呼ばれています。
非同期動作では、作業は開始しますが、その作業が終わるまで待つ(ブロックする)ことはありません。代わりに、「プレースホルダー」と呼ばれる特殊なオブジェクトをすぐに返します。このプレースホルダーは、作業が終わったときに結果を保持します。作業が終わると、プレースホルダーは「解決」され、結果が利用できるようになります。もし作業中に何か問題が起きた場合、プレースホルダーは「拒否」され、エラー情報が保持されます。
この非同期のパターンをAPIに適用したものが、「ロングランオペレーション(Long-running operation)」またはLROです。LROは、APIがバックグラウンドで行う作業を記録し、その状態を確認したり、結果を待ったり、結果を非同期に通知されるといった機能を提供します。また、進行中の作業を一時停止、再開、キャンセルする機能も提供することが多いです。これにより、APIの利用者は、APIが行う作業が複雑で時間がかかる場合でも、他の作業を進めながら結果を待つことができます。これが、ロングランオペレーションの目的となります。
結果を待つ場合とプロミスへのコールバックの追加
async function factor(value: number): Promise<number[]> {
// ...
}
async function waitOnPromise() {
let factors = await factor(...); ←①
let promise = factor(...);
let otherFactors = await promise; ←①
}
function promiseCallback() {
let promiseForFactors = factor(...): ←②
promiseForFactors.then((factors: number[]) => {
// ...
}).catch((err) => {
// ...
});
}
①ここで、結果を待つ。これは、結果を返すか、エラーを出すかのどちらかになる
②ここでは、コールバックをプロミスに追加する。これは、解決された結果と拒否によるエラーの両方を処理することができる
LROでデータをバックアップする場合のライフサイクル
まとめ
- LROは、Web API版のPromissやFuturesで、APIサービスがバックグラウンドで行っている作業をトラッキングするためのツールとして機能します。
- LROはパラメーターを持つインターフェースで、具体的な結果の型(たとえば、LROの結果得られるリソース)と、LRO自身の進捗情報を保存するためのメタデータタイプを返します。
- LROは一定時間後に結果またはエラーを返し、利用者は定期的に状態をポーリングするか、待機中に結果が通知されることでそのことを知ることができます。
- LROは、そのAPIの判断で一時停止、キャンセルすることができます。これらはカスタムメソッドで行います。
- LROは永遠に保存すべきですが、一般的には、標準的な時間(30日など)が経過したものは破棄すべきです。
参考資料
Discussion