NServiceBus:超时由多个 Sagas 处理



我们目前有一个NServiceBus 5系统,其中包含两个重复出现的Sagas。由于它们充当调度程序来定期从外部系统中提取多种数据,因此我们使用超时来触发此操作:我们创建了一个名为 ExecuteTask 的通用空类,Saga 使用它来处理超时。

public class ScheduleSaga1 : Saga<SchedulerSagaData>,
IAmStartedByMessages<StartScheduleSaga1>,
IHandleMessages<StopSchedulingSaga>,
IHandleTimeouts<ExecuteTask>

而另一个传奇几乎是相同的定义:

public class ScheduleSaga2: Saga<SchedulerSagaData>,
IAmStartedByMessages<StartScheduleSaga2>,
IHandleMessages<StopSchedulingSaga>,
IHandleTimeouts<ExecuteTask>

超时在两个传奇中处理相同:

public void Handle(StartScheduleSaga1 message)
{
if (_schedulingService.IsDisabled())
{
_logger.Info($"Task '{message.TaskName}' is disabled!");
}
else
{
Debugger.DoDebug($"Scheduling '{message.TaskName}' started!");
Data.TaskName = message.TaskName;
// Check to avoid that if the saga is already started, don't initiate any more tasks
// as those timeout messages will arrive when the specified time is up.
if (!Data.IsTaskAlreadyScheduled)
{
// Setup a timeout for the specified interval for the task to be executed.
Data.IsTaskAlreadyScheduled = true;
// Send the first Message Immediately!
SendMessage();
// Set the timeout
var timeout = _schedulingService.GetTimeout();
RequestTimeout<ExecuteTask>(timeout);
}
}
}
public void Timeout(ExecuteTask state)
{
if (_schedulingService.IsDisabled())
{
_logger.Info($"Task '{Data.TaskName}' is disabled!");
}
else
{
SendMessage();
// Action that gets executed when the specified time is up
var timeout = _schedulingService.GetTimeout();
Debugger.DoDebug($"Request timeout for Task '{Data.TaskName}' set to {timeout}!");
RequestTimeout<ExecuteTask>(timeout);
}
}

private void SendMessage()
{
// Send the Message to the bus so that the handler can handle it
Bus.Send(EndpointConfig.EndpointName, Activator.CreateInstance(typeof(PullData1Request)));
}

现在的问题是:由于两个 Sagas 都在请求 ExecuteTask 的超时,它被调度到两个 Sagas! 更糟糕的是,传奇中的有状态数据似乎被搞砸了,因为两个传奇都在发送两个消息。

因此,似乎超时被发送到所有请求它的Saga实例。 但是从示例中看 https://docs.particular.net/samples/saga/simple/没有关于多个 Saga 实例及其状态的特殊逻辑。

我的假设正确吗?如果是这种情况,让多个 Sagas 请求和接收超时的最佳实践是什么?

发生这种情况时,我能想到的唯一原因是它们共享相同的标识符来唯一标识 saga 实例。

ScheduleSaga1ScheduleSaga2都使用相同的SchedulerSagaData来存储状态。NServiceBus 看到传入消息,并尝试根据传入消息中的唯一标识符检索状态。例如,如果StartScheduleSaga1StartScheduleSaga2都带有标识符1,NServiceBus 将使用唯一标识符1在表中搜索 saga 状态SchedulerSagaData

然后,ScheduleSaga1ScheduleSaga2将共享同一行!!

超时基于TimeoutEntity表中的SagaId。因为两个传奇共享相同的SagaId,所以一旦超时到来,它们都会被执行是合乎逻辑的。

至少不应重复使用标识符来计划任务。最好不要共享同一个类来存储 saga 状态。也更容易调试。

最新更新