Подход для REST-запроса с длительным временем выполнения?
Мы создаем службу REST, выполнение которой займет около 5 минут. Он будет вызываться только несколько раз в день внутренним приложением. Существует ли проблема с использованием запроса REST (т. Е. HTTP), выполнение которого занимает 5 минут?
Должны ли мы беспокоиться о тайм-аутах? Должны ли мы запускать запрос в отдельном потоке на сервере и проводить опрос клиентов на предмет статуса?
4 ответа
Предполагая, что вы можете настроить тайм-ауты HTTP, используя любую платформу, которую вы выберете, вы можете запросить через GET и просто зависнуть на 5 минут.
Однако может быть более гибким инициировать выполнение через POST, получить квитанцию (номер / идентификатор и т. Д.), А затем выполнить GET, используя это через 5 минут (и, возможно, повторить попытку, если ваша процедура не займет ровно 5 минут). каждый раз). Если запрос все еще выполняется, верните соответствующий код ошибки HTTP (возможно, 404, но что бы вы вернули для GET с несуществующей квитанцией?) Или верните результаты, если они доступны.
Это один из подходов.
Создайте новый запрос для выполнения ProcessXYZ
POST /ProcessXYZRequests
201-Created
Location: /ProcessXYZRequest/987
Если вы хотите увидеть текущий статус запроса:
GET /ProcessXYZRequest/987
<ProcessXYZRequest Id="987">
<Status>In progress</Status>
<Cancel method="DELETE" href="/ProcessXYZRequest/987"/>
</ProcessXYZRequest>
когда запрос закончится, вы увидите что-то вроде
GET /ProcessXYZRequest/987
<ProcessXYZRequest>
<Status>Completed</Status>
<Results href="/ProcessXYZRequest/Results"/>
</ProcessXYZRequest>
Используя этот подход, вы можете легко представить, что дадут следующие запросы
GET /ProcessXYZRequests/Pending
GET /ProcessXYZRequests/Completed
GET /ProcessXYZRequests/Failed
GET /ProcessXYZRequests/Today
Как указывает Брайан Агнью, 5 минут вполне поддаются управлению, если они несколько расточительны, если можно контролировать параметры тайм-аута. В противном случае должны быть выполнены как минимум два запроса: первый, чтобы запустить процесс, производящий результат, и второй (и третий, четвертый и т. Д., Если для компиляции результата требуется больше времени, чем ожидалось), для запроса результата.
Брайан Агнью и Даррел Миллер оба предлагают похожие подходы для двух (+)- пошагового подхода: POST запрос к конечной точке фабрики, запуск задания на сервере, а затем GET результат из конечной точки возвращенного результата.
Хотя вышеприведенное является очень распространенным решением и действительно соответствует букве ограничений REST, оно очень сильно пахнет RPC. То есть вместо того, чтобы сказать "предоставьте мне представление этого ресурса", в нем говорится "запустить это задание" (RPC), а затем "предоставить мне представление ресурса, являющегося результатом выполнения задания" (REST). РЕДАКТИРОВАТЬ: я говорю очень свободно здесь. Чтобы быть ясным, ни одно из этого явно не противоречит ограничениям REST, но это очень похоже на навязывание подхода без RESTful в одежде REST, теряя его преимущества (например, кеширование, идемпотентность) в процессе.
Поэтому я бы предпочел, чтобы, когда клиент впервые попытался получить ресурс, сервер ответил 202 "Принят" ( http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html), возможно, с "попытаться вернуться через 5 минут" где-то в объекте ответа. После этого клиент может опросить ту же конечную точку, чтобы ПОЛУЧИТЬ результат, если он доступен (в противном случае вернуть еще 202 и повторить попытку позже).
Некоторые дополнительные преимущества этого подхода состоят в том, что одноразовые ресурсы (такие как задания) не создаются излишне, две отдельные конечные точки не должны запрашиваться (фабрика и результат), и аналогично вторая конечная точка не должна определяться на основе анализа ответа от во-первых, тем проще. Кроме того, результаты могут быть кэшированы "бесплатно" (по кодам). Установите время истечения срока действия кэша в заголовке результата в соответствии с тем, как долго результаты являются "действительными", в некотором смысле, для вашей проблемной области.
Хотелось бы назвать это учебным примером "ресурсно-ориентированного" подхода, но, возможно, по иронии судьбы, в главе 8 "Веб-сервисы RESTful" предлагается двухконечный, фабричный подход. Пойди разберись.
Если вы контролируете оба конца, тогда вы можете делать все, что захотите. Например, браузеры, как правило, запускают HTTP-запросы с заголовками "закрытие соединения", поэтому у вас остается меньше вариантов;-)
Имейте в виду, что если у вас есть некоторые межсетевые экраны NAT/Firewall, у вас могут быть некоторые разрываемые соединения, если они неактивны в течение некоторого времени.
Могу ли я предложить зарегистрировать процедуру "обратного вызова"? Клиент отправляет запрос с "конечной точкой обратного вызова" на сервер, получает "билет". Как только сервер завершает работу, он выполняет "обратный вызов" клиента... или клиент может проверить состояние запроса через идентификатор билета.