NServiceBus: Тайм-аут обрабатывается несколькими сагами - PullRequest
0 голосов
/ 04 июня 2018

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

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

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

1 Ответ

0 голосов
/ 05 июня 2018

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

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

Оба ScheduleSaga1 и *Затем 1014 * будет использовать одну и ту же строку !!!

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

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

...