我有一個控制器傳奇,曾經有一個步驟在一個事務中啓動一個包含3個動作的進程。我現在正在將這個子過程重構爲一個單獨的傳奇。這樣做的結果將是原始傳奇將會啓動新的「sub-saga」的多個實例(這個sub-saga也將由其他非傳奇進程通過相同的命令啓動)。我的問題是如何以最佳方式關聯傳奇故事的層次結構?如何正確關聯啓動另一個控制器傳奇的多個實例的控制器傳奇?
在下面的例子中,主要的傳奇故事將嘗試啓動具有相同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();
}
}
我看到的唯一的溶劑是改變subsaaga生成一個單獨的correlationId以及保持原始號。例如:
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,當SubSaga完成時通知MainSaga。與此問題是,另一個消費者也正在發送MySubProcessCommand而不等待完成的事件/答覆。
感謝您的回答。然後,這個sub-saga將不得不創建它自己的相關ID,我猜是okei。通常情況下,我的傳奇使用startsBy消息中的相關ID,現在看來這是錯誤的,因爲這種情況存在。 – sp1nakr
在我們的案例中,回覆將不起作用,因爲傳奇的最後一步是處理來自其他服務的消息的消息處理程序。回覆消息將因此被指向該端點,而不是主要傳奇的端點。建議使用Bus.SendLocal()方法嗎?否則,除了發佈「流程完成事件」或其他類似的問題,我不會看到另一種解決方案。 – sp1nakr
你是對的@ sp1nakr。 :)調用的正確方法是'ReplyToOriginator()',而不是'Bus.Reply()'。我已經更新了我的答案。您描述的情況與https://docs.particular.net/nservicebus/sagas/reply-replaytooriginator-differences和https://docs.particular.net/nservicebus/sagas/#notifying-callers-of-status相同。 – janovesk