1

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

在以下示例中,主 saga 将尝试启动具有相同相关 ID 的子 saga 的三个实例。即使这可行,这 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();
    }   
}

我看到的唯一解决方案是更改子传奇以生成单独的相关 ID 以及保留发起者 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();
    } 

这个问题是否有“最佳实践”解决方案?我一直在考虑使用 Bus.Reply,在子传奇完成时通知 MainSaga。问题是另一个消费者也在发送 MySubProcessCommand 而不等待完成的事件/回复。

4

1 回答 1

3

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

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

  1. 使用两个不同的命令。

让两个不同的命令启动子传奇,比如 MySubProcessFromMainSagaCommandMySubProcessFromSomewhereElseCommandIAmStartedByMessages<>一个 Saga有多个是很好的。

  1. 延长MySubProcessCommand

包括一些数据MySubProcessCommand以表明它是来自主要传奇还是其他发起者。

无论哪种方式都会为您提供足够的信息来存储子传奇是如何开始的,例如Data.WasInitatedByMainSaga. 在子传奇完成逻辑中检查这一点。如果是真的,请执行 aReplyToOriginator()与原始主要 saga 进行通信。如果没有,请跳过回复。

于 2016-10-05T21:36:18.467 回答