1

我一直在使用带有 MassTransit 的自动状态机。我喜欢使用那个状态/传奇机器,尤其是它是如何配置和设置的,以及我可以为状态机提供实现合约以用作消息的事件。

这就是它的样子:

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

有哪些类似但未连接到 MQ 架构的替代 Saga 实现?我想我真正在寻找的是至少具有内存持久存储的状态机或 Saga 实现。

4

1 回答 1

3

您可以使用完全独立于 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();
    }
}

它的创建和调用(公主模型是示例的状态实例)如下所示:

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

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

于 2015-02-25T15:16:24.377 回答