Долгосрочный API REST с очередями

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

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

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

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

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

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

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

Ответ 1

Я предполагаю, что ваша система выглядит следующим образом. У вас есть служба 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. Единственной дополнительной функцией будет подписка на уведомления, которая не меняется часто.