Является ли моя структура Saga правильным решением?(NServiceBus) - PullRequest
3 голосов
/ 26 октября 2011

Я перейду прямо к нему. Я пытаюсь автоматизировать платежи по кредитным картам через файл, отправленный в наш банк. Платежи по карте не подтверждаются в банке в режиме реального времени. Банк обрабатывает платежи в одночасье и на следующий день отправляет файл ответов как с успешными, так и с неудачными платежами.

У меня есть веб-приложение, которое, когда оно принимает или отменяет платеж, посылает сообщение, содержащее детали платежа / отмены (через Bus.Send), обработчику командных сообщений.

Затем процессор публикует (через Bus.Publish) это для всех служб, чтобы увидеть.

Одна служба должна выполнять следующие действия:

  • запустить сагу с получением первого сообщения
  • выдать запрос на тайм-аут для закрытия бизнеса
  • отслеживать все последующие сообщения по мере их поступления (в саге)
  • по получении тайм-аута превратить сообщения об оплате и отмене в файл банка.

Проблема в том, что я не знаю, как хранить коллекции сообщений (или что-нибудь еще в этом отношении) в саге, поскольку List <> не разрешен в качестве виртуальных членов.

Вот текущая структура саги:

public class PaymentRequestCancelledSagaBase : IContainSagaData
    {
        // the following properties are mandatory
        public virtual Guid Id { get; set; }
        public virtual string Originator { get; set; }
        public virtual string OriginalMessageId { get; set; }

        // List of all the received PaymentRequestedMessages
        public virtual List<PaymentRequested> PaymentRequestedMessages;

        // List of all the received PaymentCancelledMessages
        public virtual List<PaymentCancelled> PaymentCancelledMessages;
    }

Есть мысли?

1 Ответ

9 голосов
/ 26 октября 2011

Я не уверен, соответствует ли мое мышление Уди и др., Но я всегда понимал, что данные саги очень легкие метаданные о сообщениях, они не должны содержать много реальных сообщенийdata.

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

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

Сервисная шинаэто не система сама по себе, это способ для независимых систем и компонентов общаться друг с другом.Саги на самом деле предназначены для удаления после завершения (через MarkAsComplete), поэтому они действительно не место для хранения "постоянной" информации.

В моем мире данные саг выглядят примерно таквместо этого:

public class PaymentProcessingSagaData : IContainSagaData
{
    public virtual Guid Id { get; set; }
    public virtual string Originator { get; set; }
    public virtual string OriginalMessageId { get; set; }

    public virtual int RequestBatchId { get; set; }
    public virtual DateTime? WhenRequestBatchClosed { get; set; }
    public virtual string BankRequestFileName { get; set; }
    public virtual DateTime? WhenRequestFileSent { get; set; }
    public virtual string BankResponseFileName { get; set; }
    public virtual DateTime? WhenResponseFileReceived { get; set; }
    public virtual int PaymentBatchId { get; set; }
}

Это соответствует порядку операций, например:

  1. Запрос отправлен в приложение, которое создает / добавляет в пакет и отправляет событие PaymentRequested.
  2. Подписчик выбирает событие PaymentRequested и при необходимости создает новую сагу и устанавливает RequestBatchId, которая становится идентификатором корреляции саги.Затем он устанавливает тайм-аут для закрытия бизнеса.
  3. Обработчик тайм-аута закрывает пакет, устанавливает WhenRequestBatchClosed и публикует событие PaymentRequestBatchClosed.
  4. Подписчик получает событие PaymentRequestBatchClosed, создаетфайл оплаты (устанавливает BankRequestFileName), публикует событие RequestFileAvailable, сообщающее, что файл готов.
  5. Подписчик получает событие RequestFileAvailable и инициирует процесс загрузки, который (например) передает файл по FTPсервер банка обновляет WhenRequestFileSent и публикует событие RequestFileSent.
  6. Процесс мониторинга (или другой обработчик тайм-аута) обнаруживает файл ответов, обновляет BankResponseFileName и WhenResponseFileReceived и публикует событие ResponseFileAvailable.
  7. Подписчик получает событие ResponseFileAvailable, обрабатывает файл, создает пакет платежей, обновляет PaymentBatchId, а также опционально публикует итоговое событие PaymentsProcessed и завершает сагу.

Конечно, вам не обязательно нужны эти When поля DateTime, вы также можете легко иметь логические флаги, указывающие, какие шаги завершены.Но важно то, что ваша сага отслеживает транзакцию состояние , а не транзакцию data .

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

...