Как правильно соотнести сагу о контроллере, которая запускает несколько экземпляров другой саги о контроллере?
У меня есть сага о контроллере, на которой раньше был шаг, запускающий процесс, содержащий 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.
Есть два способа решить проблему запуска саги как основной сагой, так и другим инициатором.
- Используйте две разные команды.
Пусть две разные команды запускают подсагу, как MySubProcessFromMainSagaCommand
а также MySubProcessFromSomewhereElseCommand
, Хорошо иметь несколько IAmStartedByMessages<>
для саги.
- простираться
MySubProcessCommand
Включить некоторые данные в MySubProcessCommand
указать, пришло ли это из главной саги или другого инициатора.
В любом случае вы получите достаточно информации для хранения, например, запуска субсаги. Data.WasInitatedByMainSaga
, Проверьте это в логике завершения саги. Если это правда, сделайте ReplyToOriginator()
общаться обратно в исходную главную сагу. Если нет, пропустите ответ.