АналитикаСистемный анализСистемный аналитик

Система запускает операцию, которая может длиться минуты. Какой паттерн API позволит не удерживать клиентск...

Система запускает операцию, которая может длиться минуты. Какой паттерн API позволит не удерживать клиентское соединение до завершения?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

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

Такой подход отделяет прием команды от ее выполнения и не связывает жизненный цикл операции с одним сетевым соединением.

Исторический контекст

Классическая модель HTTP предполагает запрос и ответ в рамках одной операции. Она удобна для быстрых действий, но плохо подходит для обработки файлов, массовых расчетов, интеграций с медленными внешними системами и других задач с неопределенной длительностью.

В распределенных системах сетевые соединения могут закрываться по тайм-ауту, балансировщики могут ограничивать время ожидания, а клиент может временно потерять связь. Поэтому длительные операции стали моделировать как самостоятельные управляемые ресурсы.

Постановка проблемы

Если клиент ждет завершения операции в одном соединении, он может получить тайм-аут, хотя сервер продолжит работу. Повторная отправка запроса после такого тайм-аута способна запустить вторую операцию, если отдельно не определены правила повторов и идентификации.

Синхронная схема также удерживает ресурсы сервера, усложняет масштабирование и не дает клиенту надежного способа отличить состояние выполняющейся операции от потери ответа.

Подробное решение

При получении команды сервер должен быстро подтвердить, что запрос принят, создать ресурс операции и присвоить ему идентификатор. В ответе передаются начальный статус, например выполняется, и ссылка или иной адрес для получения состояния.

Ресурс операции обычно содержит статус, время создания, время завершения, результат либо ссылку на результат, а при ошибке — нормализованное описание причины. Набор состояний должен быть конечным и однозначным: например, выполняется, успешно завершена, завершена с ошибкой, отменена.

Клиент может опрашивать ресурс с увеличивающимся интервалом или подписаться на уведомление. При опросе важно определить срок хранения ресурса операции, правила ответа после его удаления и предельную частоту запросов.

Для отмены требуется отдельная явно поддержанная операция. Отправка запроса на отмену не всегда означает немедленную остановку: задача может уже перейти в необратимую фазу, поэтому API должен различать запрос на отмену и фактический статус отмененной операции.

Нужно отдельно решить вопрос повторной отправки команды. Идентификатор операции должен быть связан с исходным запросом так, чтобы повторная доставка не создавала неожиданно несколько независимых работ. Это не следует считать автоматически решенным только потому, что выполнение асинхронное.

Асинхронность повышает сложность: клиенту нужны состояния и обработка ошибок, результат может быть временно недоступен, а согласованность между созданием операции и запуском фоновой обработки требует надежного механизма передачи задания. Компромисс оправдан, когда длительность или надежность выполнения важнее простоты немедленного ответа.

Ситуация из практики

Сервис принимает архив документов на проверку, а обработка занимает от нескольких секунд до нескольких минут. Рассматривались три варианта: держать соединение открытым до результата, сразу возвращать результат и выполнять проверку позже без наблюдаемого статуса, либо создать ресурс операции.

Первый вариант прост для клиента, но подвержен тайм-аутам и расходует соединения. Второй снижает требования к API, однако клиент не понимает, завершилась ли проверка, и не может корректно получить результат или причину ошибки.

Выбран третий вариант: после приема архива создается операция со статусом выполняется, а результат становится доступен после перехода в состояние успешно завершена. Для клиентов с поддержкой уведомлений добавили callback, но ресурс операции оставили источником состояния, потому что уведомление могло потеряться.

В результате соединения не удерживались во время проверки, клиент получил единый способ отслеживать прогресс и ошибки, а повторное получение статуса не запускало обработку заново.

Что кандидаты часто упускают

  1. Вопрос: Достаточно ли вернуть клиенту идентификатор фоновой задачи?

Ответ: Нет. Идентификатор без описанного ресурса состояния не определяет, где и как узнать результат, какие статусы допустимы, когда задача считается завершенной и как трактовать ошибку. Контракт должен описывать жизненный цикл операции, формат результата, срок доступности данных и поведение для неизвестного или уже удаленного идентификатора.

  1. Вопрос: Почему одного уведомления о завершении недостаточно?

Ответ: Уведомление может не дойти из-за сетевой ошибки, временной недоступности получателя или сбоя при его обработке. Поэтому уведомление лучше рассматривать как ускоритель доставки, а не как единственный источник истины. Клиент должен иметь возможность безопасно запросить текущее состояние операции повторно.

  1. Вопрос: Как отличить временную ошибку обработки от окончательного отказа?

Ответ: В модели операции должны быть явно разделены повторяемые и окончательные состояния. Временная ошибка допускает автоматический повтор по правилам сервиса, а окончательная ошибка требует изменения входных данных или вмешательства пользователя. Если API не различает эти случаи, клиент либо будет бесконечно повторять безнадежную задачу, либо преждевременно сообщит о неуспехе там, где операция могла завершиться после повторной обработки.