Долгоживущие RESTful взаимодействия - PullRequest
3 голосов
/ 23 сентября 2008

В настоящее время в моей команде идет обсуждение, и мне будут интересны другие взгляды. Предположим, у нас есть веб-сервис RESTful, роль которого заключается в том, чтобы аннотировать документы, применяя различные алгоритмы и сервисы анализа. Основные взаимодействия понятны: у нас есть ресурс, который является коллекцией документов; клиент отправляет новый документ в коллекцию, возвращает URI нового документа, затем может ПОЛУЧИТЬ docURI для возврата документа или GET {docURI}/metadata для просмотра общих метаданных, {docURI}/ne для именованных объектов и т. д. Проблема в том, что некоторые анализы могут занять много времени. Предположим, что клиент ПОЛУЧАЕТ URI метаданных до завершения анализа, потому что он хочет иметь возможность отображать частичные или инкрементные результаты в пользовательском интерфейсе. Повторение GET в будущем может дать больше результатов.

Решения, которые мы обсудили, включают:

  • поддержание HTTP-соединения открытым пока все анализы не сделаны (что не кажется масштабируемым)
  • с помощью content-length и accept-range заголовки, чтобы получить добавочный контент (но мы не знаем заранее, как долго конечный контент будет)
  • обеспечение канал Atom для каждого ресурса, так клиент подписывается на обновление события, а не просто ПОЛУЧЕНИЕ ресурс (кажется чрезмерно сложный и возможно ресурсоемкий, если есть много активных документов)
  • просто получаю возврат все, что доступно в то время (но это все еще оставляет проблему клиента зная, когда мы наконец закончим) [отредактировано, чтобы удалить ссылку на идемпотентность после комментариев] .

Есть ли какие-либо мнения или предложения относительно альтернативных способов обработки долгоживущих или асинхронных взаимодействий в архитектуре RESTful?

Ian

Ответы [ 7 ]

3 голосов
/ 23 сентября 2008

предоставление канала Atom для каждого ресурса, чтобы клиент подписывался на обновление событий, а не просто ПОЛУЧИЛ ресурс (кажется чрезмерно сложным и, возможно, ресурсоемким, если имеется много активных документов)

Рассматривали ли вы SUP ?

Если опрос является опцией, зачем беспокоиться о подаче? Почему бы просто не сделать так, чтобы клиенты опрашивали сам ресурс?

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

3 голосов
/ 23 сентября 2008

Я бы реализовал это следующим образом:

1) клиент запрашивает метаданные
2) сервер возвращает либо фактические данные (если они уже доступны), либо маркер NotReady
3) клиент спрашивает сервер, когда будут доступны данные (этот шаг может быть объединен с предыдущим)
4) сервер возвращает временной интервал (может быть некоторая эвристика для общего числа выполняемых заданий и т. Д.)
5) клиент ожидает указанный период времени и переходит к шагу 1

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

2 голосов
/ 23 сентября 2008
  • просто игнорирование идемпотентности и получение GET возврата того, что доступно в то время (но это все еще оставляет проблему клиента, зная, когда мы наконец закончим).

Действительно ли GET, который возвращает разные результаты с течением времени, действительно означает, что он не идемпотентен? Спецификация говорит:

Методы также могут обладать свойством «идемпотентности» в том смысле, что (кроме ошибок, связанных с ошибками или истечением срока действия), побочные эффекты от N> 0 идентичных запросов такие же, как для одного запроса

То есть, несколько вызовов GET могут возвращать разные результаты, если сами вызовы не имеют побочных эффектов.

В этом случае, возможно, ваш метод REST мог бы использовать механизмы условного GET и кэширования, чтобы указать, когда это будет сделано:

  • Пока идет анализ, ответ GET {docURI}/metadata может иметь:
    • заголовок Expires будет установлен на несколько секунд в будущем.
    • no ETag header.
  • Как только анализ завершен, ответы на этот ресурс имеют:
    • no Expires header.
    • и ETag. Последующие запросы с ETag должны возвращать 304 Not Modified.

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

Это "похоже" на дизайн RESTful - вы можете представить, что веб-браузер делает правильные вещи, поскольку он делает последовательные запросы к этому ресурсу.

2 голосов
/ 23 сентября 2008

Использовать HTTP 202 Принято .

Кроме того, проверьте Веб-службы RESTful - это то, где я узнал об этом.

1 голос
/ 26 сентября 2008

Вы можете проверить Udi Dahan's nServiceBus .

1 голос
/ 24 сентября 2008

Одним из альтернативных решений, которые могут подходить или не подходить в вашем случае, является добавление новой конечной точки под названием «AnnotationRequests». Отправьте документ (или ссылку на него) в конечную точку AnnotationRequests, и он должен вернуть местоположение (например, http://example.org/AnnotationRequest/2042)), которое позволит вашему клиенту опрашивать состояние процесса. Когда процесс завершится, запрос AnnotationRequest "Представление может содержать ссылку на заполненный документ.

Одним приятным побочным эффектом этого является то, что вы можете выполнить GET для AnnotationRequests, чтобы увидеть документы, которые в данный момент обрабатываются. Вам решать, как долго вы хотите хранить запросы AnnotationRequest. Может быть полезно сохранить полную историю того, когда они были запрошены, кем и сколько времени они занимали, или могли периодически их выбрасывать.

1 голос
/ 24 сентября 2008

«просто иметь GET вернуть то, что доступно в то время», имеет массу смысла. За исключением случаев, когда они опрашивают, вы не хотите продолжать возвращать то, что они уже знают. Ответы становятся длиннее при каждом опросе.

Вам нужно, чтобы они предоставили вам "то, что я видел до сих пор" в запросе GET. Это дает вам идемпотентность. Если они просят кусок 1, они всегда получают один и тот же ответ. Как только они увидят кусок 1, они могут попросить кусок 2.

Ответ не становится больше. Больше частей становятся доступными. GET «на уровне коллекции» обеспечивает размер ответа. У вас есть GET "на уровне детализации" для каждой части, которая доступна.

По сути, это алгоритм, подобный подтверждению TCP / IP. Когда они получают кусок, вы отправляете следующий кусок. Если есть следующий кусок, в противном случае вы отправляете 200 новых сообщений для отчета.

«Проблема в том, что клиент знает, когда мы наконец закончим», не поддается решению. Они не могут знать, и вы не можете предсказать, сколько времени это займет.

Вы не хотите, чтобы они выполняли "занятое ожидание" - опрос, чтобы убедиться, что вы уже закончили - это довольно большая нагрузка на ваш сервер. Если они нетерпеливы. Вы можете задушить их запросы. Вы можете отправить им «чек обратно за х секунд», где х становится все больше.

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

Альтернативой является какая-то очередь, в которой вы отправляете результаты обратно им. Чтобы сделать это, им нужно будет предоставить URI, который вы можете POST сообщить им, что все готово.

Или они используют Atom для облегченной архитектуры опроса. В то время как Atom кажется сложным - и все еще включает опрос - вы предоставляете минимальный ответ Atom («еще не изменен») до тех пор, пока не закончите, когда вы предоставите («новые результаты»), чтобы они могли сделать реальный тяжеловес получить. Это для «все или ничего», вместо метода инкрементного ответа, описанного выше.

Вы также можете думать о GET «на уровне коллекции» как о своем статусе Atom в процессе в целом.

...