NServiceBus: тайм-аут обрабатывается несколькими сагами

В настоящее время у нас есть система NServiceBus 5, которая содержит две повторяющиеся саги. Поскольку они действуют как диспетчер для периодического извлечения различных типов данных из внешней системы, мы используем тайм-ауты, чтобы вызвать это: мы создали универсальный и пустой класс с именем 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)));
    }

Теперь проблема: поскольку обе Саги запрашивают тайм-ауты для ExecuteTask, они отправляются обеим Сагам! Хуже того, кажется, что данные с отслеживанием состояния в сагах перепутались, поскольку обе саги отправляют оба сообщения.

Поэтому кажется, что тайм-ауты отправляются всем экземплярам Saga, которые их запрашивают. Но глядя на пример https://docs.particular.net/samples/saga/simple/ нет особой логики в отношении нескольких экземпляров Saga и их состояния.

Верно ли мое предположение? Если это так, каковы наилучшие методы, чтобы несколько Sagas запрашивали и получали тайм-ауты?


person Matthias Müller    schedule 04.06.2018    source источник


Ответы (1)


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

И ScheduleSaga1, и ScheduleSaga2 используют один и тот же SchedulerSagaData для хранения состояния. NServiceBus видит входящее сообщение и пытается получить состояние на основе уникального идентификатора во входящем сообщении. Например, если и StartScheduleSaga1, и StartScheduleSaga2 входят с идентификатором 1, NServiceBus будет искать состояние саги в таблице SchedulerSagaData с уникальным идентификатором 1.

И ScheduleSaga1, и ScheduleSaga2 будут иметь одну и ту же строку!!!

Тайм-ауты основаны на SagaId в таблице TimeoutEntity. Поскольку обе саги используют один и тот же SagaId, логично, что они обе выполняются по истечении тайм-аута.

Как минимум, вы не должны повторно использовать идентификатор для планирования задач. Вероятно, лучше не использовать один и тот же класс для хранения состояния саги. Также легче отлаживать.

person Dennis van der Stelt    schedule 05.06.2018