Как правильно соотнести сагу о контроллере, которая запускает несколько экземпляров другой саги о контроллере?

У меня есть сага о контроллере, на которой раньше был шаг, запускающий процесс, содержащий 3 действия в одной транзакции. Сейчас я нахожусь в процессе реорганизации этого подпроцесса в отдельную сагу. Результатом этого будет то, что исходная сага запустит несколько экземпляров новой "подсаги" (эта подсага также будет запущена другими не-сага-процессами через ту же команду). Моя проблема в том, как наилучшим образом соотнести эту иерархию саг?

В следующем примере основная сага попытается запустить три экземпляра подсаги с одинаковым идентификатором корреляции. Даже если бы это работало, 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();
    }   
}

Единственное решение, которое я вижу, состоит в том, чтобы изменить подсагу, чтобы сгенерировать отдельный идентификатор корреляции, а также сохранить идентификатор отправителя. Например:

    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, не ожидая завершенного события / ответа.

1 ответ

Решение

Лучшая практика заключается в использовании ReplyToOriginator() в подсагах общаться обратно в главную сагу. Этот метод представлен в базовом классе Saga.

Есть два способа решить проблему запуска саги как основной сагой, так и другим инициатором.

  1. Используйте две разные команды.

Пусть две разные команды запускают подсагу, как MySubProcessFromMainSagaCommand а также MySubProcessFromSomewhereElseCommand, Хорошо иметь несколько IAmStartedByMessages<> для саги.

  1. простираться MySubProcessCommand

Включить некоторые данные в MySubProcessCommand указать, пришло ли это из главной саги или другого инициатора.

В любом случае вы получите достаточно информации для хранения, например, запуска субсаги. Data.WasInitatedByMainSaga, Проверьте это в логике завершения саги. Если это правда, сделайте ReplyToOriginator() общаться обратно в исходную главную сагу. Если нет, пропустите ответ.

Другие вопросы по тегам