2015-10-08 3 views
27

Мы внедряем REST API, который будет запускать несколько длинных backend-задач. Я читал Поваренную книгу веб-служб RESTful, и рекомендация - вернуть HTTP 202/Accepted с заголовком Content-Location, указывающим на обрабатываемую задачу. (например, http://www.example.org/orders/tasks/1234), и попросите клиента опросить этот URI для обновления в долгосрочной перспективе.Долгосрочный API REST с очередями

Идея состоит в том, чтобы API-интерфейс REST немедленно отправил сообщение в очередь, при этом рабочая роль фона собирала сообщение из очереди и разворачивала несколько задач backend, также используя очереди. Проблема, которую я вижу при таком подходе, заключается в том, как назначить уникальный идентификатор задаче, а затем позволить клиенту запросить статус задачи, выдав GET в URI Content-Location.

Если API-интерфейс REST немедленно отправляется в очередь, он может генерировать GUID и прикреплять его как атрибут к сообщению, добавляемому в очередь, но получение статуса запроса становится неудобным.

Другой вариант заключается в том, чтобы REST API сразу добавлял запись в базу данных (скажем, заказ с новым идентификатором заказа) с начальным статусом, а затем затем помещал сообщение в очередь, чтобы начать назад, которые впоследствии будут обновлять эту запись базы данных. API вернет этот новый идентификатор заказа в URI заголовка Content-Location, который клиент будет использовать при проверке состояния задачи.

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

Каким будет рекомендуемый подход?

Большое спасибо за ваши идеи.

ответ

26

Я предполагаю, что ваша система выглядит следующим образом. У вас есть служба REST, которая получает запросы от клиента. Он преобразует запросы в команды, которые может понять бизнес-логика. Вы помещаете эти команды в очередь. У вас есть один или несколько сотрудников, которые могут обрабатывать и удалять эти команды из очереди и отправлять результаты службе REST, которая может отвечать клиенту.

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

  1. Если вы хотите придерживаться опроса, вы должны создать новый ресурс REST, который содержит фактическое состояние и ход выполнения долгого задания. Это означает, что вам необходимо сохранить эту информацию в базе данных, чтобы служба REST могла отвечать на запросы, такие как GET /tasks/23461/status. Это означает, что ваш рабочий должен обновить базу данных, когда она будет завершена подзадачей или всей задачей.
  2. Если ваша служба REST работает как демон, вы можете уведомить ее о прогрессе, поэтому сохранение статуса задачи в базе данных не будет нести ответственность работника. Этот вид службы REST также может хранить информацию в памяти.
  3. Если вы решили использовать веб-порты для уведомления клиента, вы можете создать службу уведомлений. В REST вам нужно ответить идентификатором задачи. После этого вы отправляете этот идентификатор задачи в соединение с веб-сокетом, поэтому служба уведомлений будет знать, какое соединение с веб-узлом подписано на события определенной задачи. После этого вам не понадобится услуга REST, вы можете отправить прогресс через соединение с веб-сайтом, пока клиент не закрывает соединение.
  4. Вы можете объединить эти решения следующим образом. Вы разрешаете службе REST создавать ресурс задачи, чтобы вы могли получить доступ к прогрессу, используя ссылку для опроса. После этого вы отправляете обратно идентификатор с 202, который вы отправляете обратно через соединение с веб-соединениями. Таким образом, вы можете использовать службу уведомлений для уведомления клиента. По прогрессу ваш работник уведомит службу REST, которая создаст ссылку, такую ​​как GET /tasks/23461/status, и отправит эту ссылку клиенту через службу уведомлений. После этого клиент может использовать ссылку для обновления своего статуса.

Я думаю, что последнее - лучшее решение, если ваш сервис REST работает как демон. Это связано с тем, что вы можете перенести ответственность уведомления на специализированную службу уведомлений, которая может использовать веб-сайты, опросы, SSE, что бы вы ни хотели. Он может разрушиться, не убивая службу REST, поэтому служба REST останется стабильной и быстрой. Если вы также отправите ссылку с обновлением вручную с помощью 202, тогда клиент может выполнить ручное обновление (при условии, что клиент, управляемый человеком), поэтому у вас будет что-то вроде грациозного ухудшения, если служба уведомления недоступна. Вам не нужно поддерживать службу уведомлений, потому что она ничего не знает о задачах, она просто отправит данные клиентам. Ваш работник не должен знать ничего о том, как отправлять уведомления и как создавать гиперссылки. Будет также легче поддерживать клиентский код, так как он будет почти чистым клиентом REST. Единственной дополнительной функцией будет подписка на уведомления, которая не меняется часто.

+0

Большое спасибо за ваши идеи. Я все для прагматичных решений, поэтому кажется, что подход к единой базе данных будет достаточным. Модель задачи может быть расширена и для включения подзадач, если API поддерживает агрегированный запрос. Благодаря! – user2079172

+0

Спасибо за обновление и предложение! :) Эта настройка была бы надежным решением. Наши интеграторы, возможно, не смогут поддерживать соединение открытым (устаревшие системы), но, скорее всего, смогут сделать опрос. Преодоление REST API и подход 202/Accepted с служебной шиной/очередью - это разрыв для меня. В идеале служебная шина/очередь будет точкой интеграции для других систем, и API в этом случае - это еще один способ интеграции другой системы с служебной шиной (Channel Adapter). Для того, чтобы предлагаемая настройка работала, нам понадобится еще один уровень абстракции, который имеет значение – user2079172

+0

update_event, как я его вижу. Таким образом, API: 1. вставьте новую строку в таблицу update_event и верните новый идентификатор. 2: немедленно вставьте новый запрос в очередь служебной шины. Теперь клиент может опросить и т. Д. Роль рабочего 1: собирает сообщение о очереди и отправляет рабочий процесс бэкэнд. 2: как только это будет сделано, ему придется обновить таблицу update_event новым URI-реестром и т. Д. Проблема здесь в том, что рабочая роль станет осведомленной о клиенте со специальными требованиями или? Значит, он больше не является общим для системы обмена сообщениями? – user2079172

Смежные вопросы