Saga在.net中使用持久存储实现。 Masstransit Saga的替代品?

时间:2014-06-26 10:32:37

标签: .net state-machine masstransit saga

我一直在使用带有MassTransit的Automatonymous State Machine。我喜欢使用那个状态/ saga机器,特别是它是如何配置和设置的,以及我可以向状态机提供实现合同的事件以用作消息。

这就是它的样子:

 //define the statemachine with a State class (ServiceState)
 public class ServiceStateMachine :
    AutomatonymousStateMachine<ServiceState>{

    //define available states
    public State Available { get; set; }
    public State WaitForItem { get; set; }

    //define available events
    public Event<RequestItem> RequestItem { get; set; }

    //configure the state machine and configure the store to use the ServiceState class
    public void ConfigureStateMachineCorrelations(StateMachineSagaRepositoryConfigurator<ServiceState> r)

     //bind events to contracts and conditions
     r.Correlate(RequestItem,
            (state, message) =>
                state.CorrelationId == message.CorrelationId)
    }


    public ServiceStateMachine(IStateMachineActivityFactory activityFactory
    {
         State(() => Available);
         State(() => WaitForItem);

         Event(() => RequestItem);

         //bind states, events, activities, custom actions...             
         During(Available,
            When(RequestItem)
                .Then((state, message) =>
                {
                    state.ServiceId = message.ServiceId; // just an example baby!
                })
                .TransitionTo(WaitForItem)
                .Then(() => _activityFactory.GetActivity<RequestItemActivity, ServiceState>())
    }

哪些替代Saga实现有类似但没有连接到MQ架构?我想我真正想要的是状态机或Saga实现,至少有一个内存持久存储。

1 个答案:

答案 0 :(得分:2)

您可以完全独立于MassTransit(或任何消息传递系统)使用Automatonymous。无论是否有数据,都有方法(和提升函数来分解状态机或事件)来引发事件。

_machine.RaiseEvent(instance, x => x.RequestItem, itemData);

普通状态机和实例实现没有状态(实例)存储的概念,这取决于应用程序。例如,您可以在内存中键入字典,或者您可以使用NHibernate程序集,这样可以很容易地将状态实例持久化到SQL数据库(该程序集主要包括用于映射CurrentState属性的帮助程序,以及一些其他自定义类型。

这是一个在线请求的例子,我最近写的是Automatonymous最新分支(mt3)的单元测试:

class PhoneStateMachine :
    AutomatonymousStateMachine<PrincessModelTelephone>
{
    public PhoneStateMachine()
    {
        InstanceState(x => x.CurrentState);

        State(() => OffHook);
        State(() => Ringing);
        State(() => Connected);
        State(() => OnHold, Connected);
        State(() => PhoneDestroyed);

        Event(() => ServiceEstablished);
        Event(() => CallDialed);
        Event(() => HungUp);
        Event(() => CallConnected);
        Event(() => LeftMessage);
        Event(() => PlacedOnHold);
        Event(() => TakenOffHold);
        Event(() => PhoneHurledAgainstWall);

        Initially(
            When(ServiceEstablished)
                .Then(context => context.Instance.Number = context.Data.Digits)
                .TransitionTo(OffHook));

        During(OffHook,
            When(CallDialed)
                .TransitionTo(Ringing));

        During(Ringing,
            When(HungUp)
                .TransitionTo(OffHook),
            When(CallConnected)
                .TransitionTo(Connected));

        During(Connected,
            When(LeftMessage).TransitionTo(OffHook),
            When(HungUp).TransitionTo(OffHook),
            When(PlacedOnHold).TransitionTo(OnHold));

        During(OnHold,
            When(TakenOffHold).TransitionTo(Connected),
            When(PhoneHurledAgainstWall).TransitionTo(PhoneDestroyed));

        DuringAny(
            When(Connected.Enter)
                .Then(context => StartCallTimer(context.Instance)),
            When(Connected.Leave)
                .Then(context => StopCallTimer(context.Instance)));
    }


    public State OffHook { get; set; }
    public State Ringing { get; set; }
    public State Connected { get; set; }
    public State OnHold { get; set; }
    public State PhoneDestroyed { get; set; }

    public Event<PhoneServiceEstablished> ServiceEstablished { get; set; }
    public Event CallDialed { get; set; }
    public Event HungUp { get; set; }
    public Event CallConnected { get; set; }
    public Event LeftMessage { get; set; }
    public Event PlacedOnHold { get; set; }
    public Event TakenOffHold { get; set; }
    public Event PhoneHurledAgainstWall { get; set; }

    void StopCallTimer(PrincessModelTelephone instance)
    {
        instance.CallTimer.Stop();
    }

    void StartCallTimer(PrincessModelTelephone instance)
    {
        instance.CallTimer.Start();
    }
}

创建并调用它(Princess模型是示例的状态实例),如下所示:

var phone = new PrincessModelTelephone();
await _machine.RaiseEvent(phone, _machine.ServiceEstablished, new PhoneServiceEstablished {Digits = "555-1212"});

await _machine.RaiseEvent(phone, x => x.CallDialed);
await _machine.RaiseEvent(phone, x => x.CallConnected);
await _machine.RaiseEvent(phone, x => x.PlacedOnHold);

await Task.Delay(10);

await _machine.RaiseEvent(phone, x => x.HungUp);

我确信还有更多示例,但状态机与任何依赖项都是分开的,可以在任何地方使用。