如何在Masstransit状态机传奇中正确设置活动?

时间:2019-05-28 09:27:22

标签: masstransit automatonymous

几天来我一直在与这个问题作斗争,但是找不到真正可行的方法。

我的情况是我有一个状态机传奇,我想在其中运行与传奇运行相同的事务(实体框架)中的东西,以便状态和业务事物并存。

现在,我已经了解到状态机本身不应该具有任何依赖性,因此可以添加此Activity(x => x.OfInstanceType<MyActivity>)活动,该活动可以从DI容器中解析出来,并且可以具有任何依赖性(服务等)在里面。到目前为止一切顺利...

我的问题是,无论我在活动中执行什么,都无法使其正常工作。它是从容器中解析出来的,并且调用了Execute方法,但是随后退出了。
看来这里抛出了一些异常,但是显然并没有冒充测试工具。

我正在使用Microsoft的dotnet核心依赖注入库。

这是一些代码

public class MyStateMachine : MassTransitStateMachine<SagaInstance>
{
    public MyStateMachine()
    {
        InstanceState(instance => instance.CurrentState);

        Event(() => Start, x => x.CorrelateBy(saga => saga.CorrelationId, context => context.Message.CorrelationId));

        Initially(
            When(Start)
                .Activity(c => c.OfType<MyActivity>())
                .TransitionTo(Running)
                .Publish(new Started())
        );
    }   

    Event<Run> Start { get; set;} 
    State Running { get; set; }
}

public class MyActivity : Activity<SagaInstance, Run>
{
    private readonly IMyService _service;
    public MyActivity(IMyService service)
    {
        _service = service;
    }

    public async Task Execute(BehaviorContext<SagaInstance, Run> context, Behavior<SagaInstance, Run> next)
    {   
        //throw new Exception("BOO"); // uncommenting this line doesn't throw anywhere
        _service.DoThatThing();
        await next.Execute(context).ConfigureAwait(false);
    }
}

[Fact]
public async Task RunMessageSent_NonexistingSaga_StateIsRunning()
{
    var harness = new InMemoryTestHarness();
    var machine = new MyStateMachine();

    var collection = new ServiceCollection();
    collection.AddMassTransit();
    collection.RegisterInMemorySagaRepository<SagaInstance>();
    collection.RegisterSagaStateMachine<MyStateMachine, SagaInstance>();
    collection.AddScoped<MyActivity>();
    collection.AddScoped<MyService>();

    var provider = collection.BuildServiceProvider();

    harness.OnConfigureInMemoryReceiveEndpoint += cfg => cfg.StateMachineSaga(machine, provider);

    await harness.Start();

    try
    {
        var guid = CorrelationId = Guid.NewGuid();
        await harness.InputQueueSendEndpoint.Send(new Run({CorrelationId = guid}));

        var repo = provider.GetService<ISagaRepository<SagaInstance>>() as InMemorySagaRepository<SagaInstance>;
        var saga = await repo.ShouldContainSaga(s => s.Serial == serial, timeout: TimeSpan.FromSeconds(1));

        Assert.NotNull(saga);
        // this Equal fails saying the saga is in state Initial
        Assert.Equal(machine.Running.Name, repo[saga.Value].Instance.CurrentState);
    }
    finally
    {
        await harness.Stop();
    }   
}

2 个答案:

答案 0 :(得分:0)

我在dotnet core 2.1上运行,经过大量搜索和浏览Masstransit存储库后,我意识到最新的(5.3)Masstransit中有更好的Dependency Injection框架API,我不想升级。首先避免必须同时将dotnet运行时依赖项升级到2.2。

完成升级后,我开始意识到必须存在一些异步问题,因为有时我会随机工作。然后我意识到内存中有另一种方法称为ShouldContainSagaInState

因此,通过使用此行,我可以正常工作!

var saga = await repo.ShouldContainSagaInState(guid, machine, x => x.Running, TimeSpan.FromSeconds(1));

还使用请求/响应模式按照我打算的方式运行代码,潜在的异常作为故障消息发送回调用方。在测试工具中,此消息以某种方式可用,但是我尚未研究检查它的正确方法。

答案 1 :(得分:0)

我已经创建了一个简单的活动,并在IOC中注册了它,就像您所做的那样,但是有一个例外:

GreenPipes.PayloadNotFoundException: The payload was not found: Automatonymous.IStateMachineActivityFactory
   at GreenPipes.PipeExtensions.GetPayload[TPayload](PipeContext context)
   at Automatonymous.Activities.ContainerFactoryActivity`3.Automatonymous.Activity<TInstance,TData>.Execute(BehaviorContext`2 context, Behavior`2 next)
   at Automatonymous.Activities.DataConverterActivity`2.Automatonymous.Activity<TInstance>.Execute[T](BehaviorContext`2 context, Behavior`2 next)
   at Automatonymous.Behaviors.LastBehavior`1.Automatonymous.Behavior<TInstance>.Execute[T](BehaviorContext`2 context)
   at Automatonymous.States.StateMachineState`1.Automatonymous.State<TInstance>.Raise[T](EventContext`2 context)
   at Automatonymous.States.StateMachineState`1.Automatonymous.State<TInstance>.Raise[T](EventContext`2 context)
   at Automatonymous.AutomatonymousStateMachine`1.Automatonymous.StateMachine<TInstance>.RaiseEvent[T](EventContext`2 context)
   at Automatonymous.Pipeline.StateMachineSagaMessageFilter`2.Send(SagaConsumeContext`2 context, IPipe`1 next)
   at MassTransit.EntityFrameworkCoreIntegration.Saga.EntityFrameworkSagaRepository`1.MassTransit.Saga.ISagaRepository<TSaga>.Send[T](ConsumeContext`1 context, ISagaPolicy`2 policy, IPipe`1 next)

我使用Masstransit 5.1.5 有什么问题吗?