什么是传奇,为什么他们使用事件驱动的架构?

时间:2017-01-13 10:37:07

标签: domain-driven-design nservicebus-sagas eda

我遇到了以下代码:

  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();
            }
      }
}

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

第一个查询似乎得到了解答。但他们真正属于责任范围,即基础设施?领域? 。这些仅适用于EDA吗?

1 个答案:

答案 0 :(得分: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 bus sagas并不适合prior use of the term

  

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

     
      
  • 有一个众所周知的,预先存在的saga一词的定义,其含义与通常与CQRS有关的含义不同。
  •   
  • 术语流程管理器是对此类代码工件执行的角色的更好描述。
  •