3

我会直接切入。我正在尝试通过发送给我们银行的文件自动执行信用卡付款。银行卡付款未实时验证。银行在一夜之间处理付款,并在第二天发送一个响应文件,其中包含成功和不成功的付款。

我有一个网络应用程序,当它接受或取消付款时,会(通过 Bus.Send)将包含付款/取消详细信息的消息发送到命令消息处理器。

然后处理器发布(通过 Bus.Publish)这个给所有服务看。

一项服务需要执行以下操作:

  • 收到第一条消息后开始一个 saga
  • 发出关闭业务的超时请求
  • 跟踪所有后续消息(在 saga 中)
  • 收到超时后,将付款和取消消息转入银行文件。

问题是我不知道如何在 saga 中存储消息集合(或其他任何内容),因为 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;
    }

有什么想法吗?

4

1 回答 1

9

我不确定我的想法是否与 Udi 等人一致,但我一直认为 saga 数据是关于消息的非常轻量级的元数据,它不应该包含太多实际的消息数据。

可以为每个付款请求和相应的批准/取消设置一个传奇,但假设银行要求您在每个工作日将它们全部批量处理,或者每个文件向您收取固定金额,这很常见......

在这种情况下,在消息传递系统 (NServiceBus) 的基础上,您可能会或应该拥有某种事务系统,该系统实际上正在跟踪事务本身。如果它们被分组到某种类型的批次中(即一个工作日),那么该批次必须有一个 ID。就是 saga 应该参考的内容,以及关于整个过程状态的基本信息(即您是否收到银行的回复?)。

服务总线本身并不是一个系统,它是独立系统和组件相互通信的一种方式。Sagas 实际上打算在完成后(通过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事件,并在必要时创建一个新的 saga 并设置RequestBatchId,这将成为 saga 相关 ID。然后它设置关闭业务的超时时间。
  3. 超时处理程序关闭批处理、设置WhenRequestBatchClosed并发布PaymentRequestBatchClosed事件。
  4. 订阅者获取PaymentRequestBatchClosed事件,创建支付文件(sets BankRequestFileName),发布一个RequestFileAvailable表明文件准备好的事件。
  5. 订阅者获取RequestFileAvailable事件并启动上传过程,该过程(例如)将文件 FTP 到银行服务器,更新WhenRequestFileSent和发布RequestFileSent事件。
  6. 监控进程(或另一个超时处理程序)检测响应文件、更新BankResponseFileNameWhenResponseFileReceived发布ResponseFileAvailable事件。
  7. 订阅者获取ResponseFileAvailable事件、处理文件、创建付款批次、更新PaymentBatchId,并可选择发布最终PaymentsProcessed事件并完成传奇。

当然,您不一定需要这些WhenDateTime 字段,您可以轻松地使用布尔标志来指示哪些步骤已完成。但重要的是,您的 saga 跟踪的是交易状态,而不是交易数据

不要犯试图将所有内容都塞进传奇的错误。它并不是要取代事务系统,它只是将它们结合在一起的一点粘合剂。

于 2011-10-26T04:52:56.197 回答