如何正确关联启动另一个控制器传奇的多个实例的控制器传奇

本文关键字:传奇 控制器 实例 何正确 关联 另一个 启动 | 更新日期: 2023-09-27 18:11:47

我有一个控制器传奇,它曾经在一个事务中有一个步骤启动一个包含3个动作的流程。我现在正在将这个子过程重构为一个单独的传奇。这样做的结果是,原始的传奇将启动新"子传奇"的多个实例(该子传奇也将由其他非传奇进程通过相同的命令启动)。我的问题是如何以最好的方式将这些传奇的等级联系起来?

在下面的示例中,主传奇将尝试启动具有相同correlationId的子传奇的三个实例。即使这是有效的,3个实例也会通过处理来自所有实例的"完成事件"而相互干扰。

public class MyMainSaga : Saga<MyMainSagaData>, 
    IAmStartedByMessages<MyMainCommand>,
    IHandleMessage<MySubProcessCommandCompletedEvent>
{
    protected override void ConfigureHowToFindSaga(SagaPropertyMapper<MyMainSagaData> mapper)
    {
        mapper.ConfigureMapping<MyMainCommandCompletedEvent>(message => message.CorrelationId).ToSaga(data => data.CorrelationId);
    }
    public void Handle(MyMainCommand message)
    {
        Data.CorrelationId = message.CorrelationId;
        foreach (var item in message.ListOfObjectsToProcess)
        {
            Bus.Send(new MySubProcessCommand{
                CorrelationId = Data.CorrelationId,
                ObjectId = item.Id
            });
        }
    }
    public void Handle(MySubProcessCommandCompletedEvent message)
    {
        SetHandledStatus(message.ObjectId);
        if(AllObjectsWhereProcessed())
            MarkAsComplete();     
    }       
}

public class MySubSaga : Saga<MySubSagaData>, 
    IAmStartedByMessages<MySubProcessCommand>,
    IHandleMessage<Step1CommandCompletedEvent>,
    IHandleMessage<Step2CommandCompletedEvent>,
    IHandleMessage<Step3CommandCompletedEvent>
{
    protected override voidConfigureHowToFindSaga(SagaPropertyMapper<MySubSagaData> mapper)
    {
        mapper.ConfigureMapping<Step1CommandCompletedEvent>(message => message.CorrelationId).ToSaga(data => data.CorrelationId);
        mapper.ConfigureMapping<Step2CommandCompletedEvent>(message => message.CorrelationId).ToSaga(data => data.CorrelationId);
        mapper.ConfigureMapping<Step3CommandCompletedEvent>(message => message.CorrelationId).ToSaga(data => data.CorrelationId);
    }
    public void Handle(MySubProcessCommand message)
    {
        Data.CorrelationId = message.CorrelationId;
        Data.ObjectId = message.ObjectId;
        Bus.Send(new Step1Command{
            CorrelationId = Data.CorrelationId;  
        });
    }
    public void Handle(Step1CommandCompletedEvent message)
    {
        Bus.Send(new Step2Command{
            CorrelationId = Data.CorrelationId;  
        });
    }
    public void Handle(Step2CommandCompletedEvent message)
    {
        Bus.Send(new Step3Command{
            CorrelationId = Data.CorrelationId;  
        });
    }
    public void Handle(Step3CommandCompletedEvent message)
    {
        Bus.Publish<MySubProcessCommandCompletedEvent>(e => {
            e.CorrelationId = Data.CorrelationId;
            e.ObjectId = Data.ObjectId;
        });
        MarkAsComplete();
    }   
}

我看到的唯一解决方案是更改子传奇以生成一个单独的correlationId,并保留原始id。例句:

    public void Handle(MySubProcessCommand message)
    {
        Data.CorrelationId = Guid.NewGuid();
        Data.OriginatorCorrelationId = message.CorrelationId;
        Data.ObjectId = message.ObjectId;
        Bus.Send(new Step1Command{
            CorrelationId = Data.CorrelationId;  
        });
    }
    public void Handle(Step1CommandCompletedEvent message)
    {
        Bus.Send(new Step2Command{
            CorrelationId = Data.CorrelationId;  
        });
    }
    public void Handle(Step2CommandCompletedEvent message)
    {
        Bus.Send(new Step3Command{
            CorrelationId = Data.CorrelationId;  
        });
    }
    public void Handle(Step3CommandCompletedEvent message)
    {
        Bus.Publish<MySubProcessCommandCompletedEvent>(e => {
            e.CorrelationId = Data.OriginatorCorrelationId;
            e.ObjectId = Data.ObjectId;
        });
        MarkAsComplete();
    } 

这个问题有"最佳实践"解决方案吗?我一直在考虑乘公交车。回复,当子传奇完成时通知主传奇。这样做的问题是,另一个消费者也在发送MySubProcessCommand而没有等待完成的事件/回复。

如何正确关联启动另一个控制器传奇的多个实例的控制器传奇

最佳实践是在子传奇中使用ReplyToOriginator()与主传奇通信。此方法在Saga基类上公开。

有两种方法可以解决由主传奇和不同的发起者启动子传奇的问题。

  1. 使用两个不同的命令

让两个不同的命令启动子传奇,如MySubProcessFromMainSagaCommandMySubProcessFromSomewhereElseCommand。一个Saga可以有多个IAmStartedByMessages<>

扩展MySubProcessCommand

MySubProcessCommand中包含一些数据,以表明它是来自主saga还是其他发起者。

这两种方式都会给您足够的信息来存储子传奇是如何开始的,例如Data.WasInitatedByMainSaga。在子传奇完成逻辑中检查这一点。如果为真,执行ReplyToOriginator()以与原始主saga通信。