Вызвать NServiceBus Saga как единый ожидаемый запрос-ответ - PullRequest
0 голосов
/ 09 декабря 2018

Рассмотрим веб-приложение, которое реализовало каждое действие базы данных, кроме запроса (то есть добавления, обновления, удаления), как сообщение NServiceBus, так что всякий раз, когда пользователь вызывает веб-API, в серверной части оно будет отображаться на await endpointInstance.Requestметод возврата ответа в том же соединении HTTP-запроса.

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

В итоге я использовал Saga для реализации обработчиков сообщений, которые основаны на некоторых других ответах обработчиков сообщений.Но проблема с Saga заключается в том, что я не могу отправить результат в том же HTTP-запросе, потому что Saga использует шаблон публикации / подписки.

Все наши веб-API должны отвечать на один и тот же HTTP-запрос (соединениедолжен оставаться открытым до тех пор, пока не будет получен результат или не возникнет исключение тайм-аута).Есть ли какое-нибудь чистое решение (желательно без использования Saga)?

Пример сценария:

  1. вызов пользователя http://test.com/purchase?itemId=5&paymentId=133
  2. вызовы веб-сервера await endpointInstance.Request<PurchaseResult>(new PurchaseMessage(itemId, paymentId));
  3. PurchaseMessage обработчик должен вызвать await endpointInstance.Request<AddPaymentResult>(new AddPaymentMessage(paymentId));
  4. , если AddPaymentResult был успешным, сохранить детали покупки в базе данных и вернуть true как PurchaseResult, в противном случае вернуть false

1 Ответ

0 голосов
/ 10 декабря 2018

Вы пытаетесь достичь чего-то, что мы (в частности Software) пытаемся активно предотвращать.Позвольте мне объяснить.

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

Тем не менее, люди делают это по разным причинам.Иногда потому, что вы хотите использовать WebAPI (или «старомодный» веб-сервис), потому что он предлагает функциональность, которую вы не хотите разрабатывать.Самый старый пример в книге - это поиск адреса по почтовому индексу.Или вычитать деньги с чьего-либо банковского счета.Если вы создаете CRM, вы можете использовать эти удаленные компоненты.В наши дни многие люди строят распределенные монолиты, потому что на конференциях их учат, что это хорошо.На диаграмме архитектуры это выглядит действительно хорошо, но все еще существует временная связь, которая может вызвать много головных болей.

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

Решением этой проблемы является асинхронная связь.Вы отправляете некоторую информацию через fire-and-Forgot.Это решает временную связь.Вместо того, чтобы иметь базу данных, которая получает десятки и десятки запросов на обновление данных и т. Д., И в результате ваш сайт останавливается, у вас есть различные варианты, чтобы убедиться, что этого не произойдет.Это действительно хорошая вещь, потому что вместо одной атомарной операции у вас есть различные мелкие операции и множество способов распределенной работы, масштабирования вашей системы и т. Д., И т. Д.

Это также создает дополнительные проблемы, потому что не всеумеет работать с огнем и забыть.Некоторые системы, которые уже были построены, пытаются ввести асинхронную связь через обмен сообщениями (и, надеюсь, NServiceBus).Некоторые части могут работать без проблем с этим.Но другие части не могут.В основном пользовательский интерфейс (UI).Потому что он был построен, чтобы получить немедленный результат.Поэтому, когда вы отправляете сообщение из пользовательского интерфейса, вы ожидаете результата!

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

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

  1. использовать вызов http://test.com/purchase?itemId=5&paymentId=133
  2. вызовы веб-сервера await endpointInstance.Request<PurchaseResult>();
  3. PurchaseMessage обработчик получает информациюон нуждается и отправляет или публикует сообщение для других компонентов, а затем отвечает обратно на веб-сервер с ответом.
  4. Следующий обработчик работает с отправленным / опубликованным сообщением и продолжает процесс

Дайте нам знать, если вам нужна дополнительная информация.Вы всегда можете связаться с нами, отправив письмо на support@particular.net

...