Azure SDK for Java での実行時間の長い操作

この記事では、JavaのAzure SDKで実行時間の長い操作について説明し、手動ポーリング ロジックを少なくして進行状況を追跡し、最終的な結果を取得する方法について説明します。

Azureに対する特定の操作は、完了するまでに長い時間がかかります。 これらの操作は、標準の HTTP スタイルのクイック要求と応答フローには従いません。 たとえば、ソース URL からストレージ BLOB にデータをコピーしたり、モデルをトレーニングしてフォームを認識したりする操作は、数秒から数分かかる場合があります。 これらの操作は実行時間の長い操作であり、多くの場合、LRO と省略されます。 LRO は、要求された操作とサーバーが実行する必要があるプロセスによっては、秒、分、時間、日、または長い時間がかかる場合があります。

AzureのJava クライアント ライブラリでは、実行時間の長い操作はすべて begin プレフィックスで始まります。 このプレフィックスは、操作の実行時間が長く、この操作との対話手段が通常の要求と応答のフローとは少し異なっていることを示します。 beginプレフィックスと共に、操作からの戻り値の型も通常とは異なり、実行時間の長い操作機能の全範囲を有効にします。 JavaのAzure SDKのほとんどの場合と同様に、実行時間の長い操作には同期 API と非同期 API の両方があります。

  • 同期クライアントでは、実行時間の長い操作は SyncPoller インスタンスを返します。
  • 非同期クライアントでは、実行時間の長い操作は PollerFlux インスタンスを返します。

SyncPollerPollerFluxはどちらも、実行時間の長いサーバー側操作との対話を簡略化するクライアント側の抽象化です。 この記事の残りの部分では、これらの型を使用する場合のベスト プラクティスについて説明します。

実行時間の長い同期操作

SyncPollerを返す API を呼び出すと、実行時間の長い操作がすぐに開始されます。 API は SyncPoller をすぐに返します。そのため、実行時間の長い操作の進行状況を監視し、最終的な結果を取得できます。 次の例は、 SyncPollerを使用して実行時間の長い操作の進行状況を監視する方法を示しています。

SyncPoller<UploadBlobProgress, UploadedBlobProperties> poller = syncClient.beginUploadFromUri(<URI to upload from>);
PollResponse<UploadBlobProgress> response;

do {
    response = poller.poll();
    System.out.println("Status of long running upload operation: " + response.getStatus());
    Duration pollInterval = response.getRetryAfter();
    TimeUnit.MILLISECONDS.sleep(pollInterval.toMillis());
} while (!response.getStatus().isComplete());

この例では、poll()SyncPoller メソッドを使用して、実行時間の長い操作の進行状況に関する情報を取得します。 このコードはコンソールに状態を出力しますが、より優れた実装により、この状態に基づいて関連する決定が行われます。

getRetryAfter() メソッドは、次のポーリングまでの待機時間に関する情報を返します。 Azure の実行時間の長い操作のほとんどは、HTTP 応答の一部としてポーリングの遅延 (つまり、一般的に使用される retry-after ヘッダー) を返します。 応答にポーリングの遅延が含まれていない場合、 getRetryAfter() メソッドは実行時間の長い操作を呼び出すときに指定された期間を返します。

前の例では、 do..while ループを使用して、実行時間の長い操作が完了するまで繰り返しポーリングします。 これらの中間結果に関心がない場合は、代わりに waitForCompletion()を呼び出すことができます。 この呼び出しは、実行時間の長い操作が完了し、最後のポーリング応答を返すまで、現在のスレッドをブロックします。

PollResponse<UploadBlobProgress> response = poller.waitForCompletion();

最後のポーリング応答で実行時間の長い操作が正常に完了したことが示されている場合は、次の getFinalResult()を使用して最終的な結果を取得できます。

if (LongRunningOperationStatus.SUCCESSFULLY_COMPLETED == response.getStatus()) {
    UploadedBlobProperties result = poller.getFinalResult();
}

SyncPollerのその他の便利な API は次のとおりです。

  • waitForCompletion(Duration): 指定されたタイムアウト時間の間、長時間実行される操作が完了するまで待機します。
  • waitUntil(LongRunningOperationStatus): 指定された実行時間の長い操作の状態が受信されるまで待ちます。
  • waitUntil(LongRunningOperationStatus, Duration): 指定された実行時間の長い操作の状態が受信されるまで、または指定されたタイムアウト期間が経過するまで待ちます。

実行時間の長い非同期操作

次の例は、 PollerFlux 実行時間の長い操作を観察する方法を示しています。 非同期 API では、ネットワーク呼び出しは、 subscribe()を呼び出すメイン スレッドとは異なるスレッドで発生します。 このアーキテクチャは、結果が使用可能になる前にメイン スレッドが終了する可能性があることを意味します。 非同期操作が完了する前に、アプリケーションが終了しないようにする必要があります。

非同期 API はすぐに PollerFlux を返しますが、実行時間の長い操作自体は、 PollerFluxをサブスクライブするまで開始されません。 このプロセスは、すべての Fluxベースの API の動作方法です。 次の例は、非同期の実行時間の長い操作を示しています。

asyncClient.beginUploadFromUri(...)
    .subscribe(response -> System.out.println("Status of long running upload operation: " + response.getStatus()));

次の例では、実行時間の長い操作で断続的な状態の更新を取得します。 これらの更新プログラムを使用して、実行時間の長い操作が想定どおりに動作しているかどうかを判断できます。 この例では、状態をコンソールに出力しますが、より適切な実装では、この状態に基づいて関連するエラー処理の決定が行われます。

中間状態の更新に関心がない場合に、最終的な結果が到着したときに通知を受け取るだけの場合は、次の例のようなコードを使用します。

asyncClient.beginUploadFromUri(...)
    .last()
    .flatMap(response -> {
        if (LongRunningOperationStatus.SUCCESSFULLY_COMPLETED == response.getStatus()) {
            return response.getFinalResult();
        }
        return Mono.error(new IllegalStateException("Polling completed unsuccessfully with status: "+ response.getStatus()));
    })
    .subscribe(
        finalResult -> processFormPages(finalResult),
        ex -> countDownLatch.countDown(),
        () -> countDownLatch.countDown());

このコードでは、 last()を呼び出して、実行時間の長い操作の最終的な結果を取得します。 この呼び出しは、すべてのポーリングが完了するまで待機することを PollerFlux に通知します。 この時点で、実行時間の長い操作は終了状態に達し、その状態を調べて結果を確認できます。 ポーラーが長時間実行される操作の正常終了を示した場合は、最終結果を取得し、subscribe 呼び出しでコンシューマーに渡すことができます。

次のステップ

Azure SDK for Java で実行時間の長い API について理解したら、HTTP クライアントをさらにカスタマイズする方法については、 Azure SDK for Java でのプロキシの構成 に関するページを参照してください。