0

我遇到了以下代码:

  public class ShippingSaga : Saga<ShippingSagaData>,
         ISagaStartedBy<OrderAccepted>,
         ISagaStartedBy<CustomerBilledForOrder>
     {
        public void Handle(CustomerBilledForOrder message)
         {
             this.Data.CustomerHasBeenBilled = true;
             this.Data.CustomerId = message.CustomerId;
             this.Data.OrderId = message.OrderId;

             this.CompleteIfPossible();

        }

        public void Handle(OrderAccepted message)
        {
            this.Data.ProductIdsInOrder = message.ProductIdsInOrder;
            this.Data.CustomerId = message.CustomerId;
            this.Data.OrderId = message.OrderId;

            this.CompleteIfPossible();
        }

        private void CompleteIfPossible()
        {
            if (this.Data.ProductIdsInOrder != null && this.Data.CustomerHasBeenBilled)
            {
                this.Bus.Send<ShipOrderToCustomer>(
                    (m =>
                    {
                        m.CustomerId = this.Data.CustomerId;
                        m.OrderId = this.Data.OrderId;
                        m.ProductIdsInOrder = this.Data.ProductIdsInOrder;
                    }
                    ));

                this.MarkAsComplete();
            }
      }
}

从上面代码中的事物看,sagas 似乎是某种更高级别的事件协调器/控制器。这是真的吗?如果是这样,它们是否仅用于事件驱动架构?最后,传奇是基础设施的一部分吗?

第一个问题似乎得到了回答。但就责任(即基础设施)而言,它们真正属于哪里?领域 ?. 这些是否仅适用于 EDA?

4

1 回答 1

3

警告:存在一些混淆,尤其是围绕对“Saga”的定义;见下文。

流程管理器从根本上说是读取模型——您从事件历史记录中重新定义它们,并查询它们以获取应该运行的命令列表。

它们类似于人类查看视图并向写入模型发送命令。有关此观点的更多信息,请参阅 Rinat Abdullin 的文章Evolving Business Processes

它们用作业务流程的描述,也就是说,它们标识了应该由聚合运行的附加决策(命令)。在实现中,它们是非常多的状态机——给定事件 X 和事件 Y,进程管理器处于状态 (XY),并且它将推荐的​​命令是固定的。

如果您将状态机(纯逻辑)与副作用(与总线的交互)分开,我发现它们更容易思考。

public class ShippingSaga : Saga,
     ISagaStartedBy<OrderAccepted>,
     ISagaStartedBy<CustomerBilledForOrder>
{
    public void Handle(CustomerBilledForOrder message)
    {
        this.process.apply(message);
        this.CompleteIfPossible();
    }

    public void Handle(OrderAccepted message)
    {
        this.process.apply(message);
        this.CompleteIfPossible();
    }

    private void CompleteIfPossible()
    {
        this.process.pendingCommands().each ( m=>
            this.Bus.Send(m);
        }
    }
}

或者等价地——如果你更喜欢考虑不可变的数据结构

public class ShippingSaga : Saga,
     ISagaStartedBy<OrderAccepted>,
     ISagaStartedBy<CustomerBilledForOrder>
{
    public void Handle(CustomerBilledForOrder message)
    {
        this.process = this.process.apply(message);
        this.CompleteIfPossible();
    }

    public void Handle(OrderAccepted message)
    {
        this.process = this.process.apply(message);
        this.CompleteIfPossible();
    }

    private void CompleteIfPossible()
    {
        this.process.pendingCommands().each ( m=>
            this.Bus.Send(m);
        }
    }
}

因此,运输过程是根据业务域定义的,NServiceBus“Saga”将该业务域与总线基础设施接口。关注点分离不是很好吗。

我在引号中使用“Saga”是因为 -- NService 总线 sagas不是特别适合该术语的先前使用

saga 一词通常用于 CQRS 的讨论中,指的是在有界上下文和聚合之间协调和路由消息的一段代码。但是,出于本指南的目的,我们更喜欢使用术语流程管理器来指代这种类型的代码工件。有两个原因:

  • saga 一词有一个众所周知的预先存在的定义,其含义与通常理解的与 CQRS 相关的含义不同。
  • 术语流程管理器更好地描述了这种类型的代码工件所执行的角色。
于 2017-01-13T15:52:11.510 回答