Длительные операции в пакете SDK Azure для Java

В этой статье объясняется длительные операции в Azure SDK для Java и показано, как отслеживать ход выполнения и получать конечные результаты с меньшей логикой опроса вручную.

Для выполнения некоторых операций с Azure требуется длительное время. Эти операции не соответствуют стандартному стилю HTTP быстрого запроса и потока ответа. Например, копирование данных из исходного URL-адреса в большой двоичный объект хранилища или обучение модели для распознавания форм — это операции, которые могут занять несколько секунд до нескольких минут. Эти операции относятся к длительным операциям и часто обозначаются аббревиатурой LRO. LRO может занять секунды, минуты, часы, дни или больше времени, в зависимости от запрошенной операции и процесса, который должен выполнять сервер.

В клиентских библиотеках Java для Azure все длительные операции начинаются с begin префикса. Этот префикс указывает, что операция выполняется долго, и что средства взаимодействия с этой операцией немного отличаются от обычного потока запросов и ответа. Наряду с префиксом begin, возвращаемый тип операции также отличается от обычного, чтобы обеспечить полную функциональность длительных операций. Как и в большинстве случаев в Azure SDK для Java, длительные операции имеют синхронные и асинхронные API:

  • В синхронных клиентах длительные операции возвращают SyncPoller экземпляр.
  • В асинхронных клиентах длительно выполняющиеся операции возвращают экземпляр PollerFlux.

И SyncPoller, и PollerFlux являются клиентскими абстракциями, которые упрощают взаимодействие с длительно выполняемыми серверными операциями. Остальная часть этой статьи описывает рекомендации при работе с этими типами.

Синхронные длительные операции

При вызове API, возвращающего объект SyncPoller, длительная операция запускается сразу. 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();
}

Другие полезные API SyncPoller включают:

  • waitForCompletion(Duration): дождитесь завершения длительной операции в течение указанного тайм-аута.
  • waitUntil(LongRunningOperationStatus): дождитесь получения состояния указанной долгосрочной операции.
  • waitUntil(LongRunningOperationStatus, Duration): дождитесь, пока будет получен статус указанной длительной операции, или до истечения указанного времени ожидания.

Асинхронные длительные операции

В следующем примере показано, как PollerFlux позволяет отслеживать длительную операцию. В асинхронных API сетевые вызовы выполняются в другом потоке, отличном от основного потока, вызывающего subscribe(). Эта архитектура означает, что основной поток может завершиться до того, как результат будет доступен. Необходимо убедиться, что приложение не завершает работу до завершения асинхронной операции.

Асинхронный API сразу возвращает PollerFlux, но сама длительная операция не запускается, пока вы не подпишетесь на PollerFlux. Этот процесс объясняет, как работают все API, основанные на Flux. В следующем примере показана асинхронная длительно выполняющаяся операция.

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, что нужно дождаться завершения всех операций опроса. На этом этапе длительно выполняемая операция достигает конечного состояния, и вы можете проверить её статус, чтобы определить результат. Если опрашиватель указывает, что длительная операция выполнена успешно, вы можете получить окончательный результат и передать его потребителю в вызове подписки.

Дальнейшие шаги

Теперь, когда вы знакомы с длинными API в Azure SDK для Java, см. статью "Настройка прокси-серверов в пакете SDK Azure для Java", чтобы узнать, как настроить HTTP-клиент дальше.