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

Эта статья содержит общие сведения о выполнении длительных операций с помощью Azure SDK для Java.

Некоторые операции в Azure могут выполняться довольно долгое время. Такие операции плохо подходят стандартному стилю работы с HTTP, то есть потоку быстрого обмена запросами и ответами. Например, такие операции, как копирование данных из исходного URL-адреса в большой двоичный объект в хранилище или обучение модели для распознавания геометрических фигур, могут выполняться несколько секунд или даже минут. Такие операции называются длительными операциями (Long-Running Operation, 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();
}

В SyncPoller есть и другие полезные API:

  1. waitForCompletion(Duration): ожидает завершения длительной операции в течение заданного времени ожидания.
  2. waitUntil(LongRunningOperationStatus): ожидает наступления указанного состояния длительной операции.
  3. 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, что нужно дождаться завершения всех опросов, то есть окончательного состояния длительной операции, чтобы вы смогли проверить ее состояние и определить результат. Если модуль опроса сообщит, что длительная операция успешно завершена, вы можете получить окончательный результат и передать его объекту-получателю в вызове subscribe.

Следующие шаги

Теперь, когда вы ознакомились с функциональными возможностями API длительных операций в Azure SDK для Java, переходите к статье Настройка прокси-серверов в пакете Azure SDK для Java, где описаны дополнительные возможности по настройке HTTP-клиентов.