Тайм-аут саги Nservicebus

У меня есть сага, которая проверяет статус вызовов API каждые 30 секунд, если статус, возвращенный из вызова, успешен, сага заканчивается, если нет, сага ждет 30 секунд и пытается снова. Если вызов API не вернул успешный ответ в течение 60 минут, сага завершается по тайм-ауту.

У меня проблемы с запуском 60-минутного тайм-аута. Код у меня есть

public class MonitorSubmissionFeedSagaData: IContainSagaData
{
    public Guid Id { get; set; }

    public string Originator { get; set; }

    public string OriginalMessageId { get; set; }

    public bool TimeoutSet { get; set; }

    [Unique]
    public string JobId { get; set; }
}

public class MonitorSubmissionFeedSaga : Saga<MonitorSubmissionFeedSagaData>,
    IAmStartedByMessages<MonitorFeedSubmissonCommand>,
    IHandleMessages<StartCheckSubmissionCommand>,
    IHandleTimeouts<MonitorSubmissionFeedSagaTimeout>
{
    public const int SagaTimeoutInMinutes = 60;

    public IEmpathyBrokerClientApi PostFileService { get; set; }

    protected override void ConfigureHowToFindSaga(SagaPropertyMapper<MonitorSubmissionFeedSagaData> mapper)
    {
        mapper.ConfigureMapping<MonitorFeedSubmissonCommand>(x => x.JobId).ToSaga(saga => saga.JobId);

    }

    public void Handle(MonitorFeedSubmissonCommand message)
    {
        Data.JobId = message.JobId;

        CheckTimeout();

        Bus.Send(new StartCheckSubmissionCommand
        {
            JobId = Data.JobId
        });
    }

    public void Handle(StartCheckSubmissionCommand message)
    {
        Log.Info("Saga with JobId {0} received", Data.JobId);

        bool isCompleted = GetJobStatus(message.JobId);

        while (isCompleted)
        {
            Thread.Sleep(30000);
            isCompleted = GetJobStatus(message.JobId);
        }

        MarkAsComplete();
    }

    public void CheckTimeout()
    {
        RequestTimeout<MonitorSubmissionFeedSagaTimeout>(TimeSpan.FromMinutes(SagaTimeoutInMinutes));
    }

    public void Timeout(MonitorSubmissionFeedSagaTimeout state)
    {
        MarkAsComplete();
    }

    bool GetJobStatus(string jobId)
    {
        return false;
        var status = PostFileService.GetJobIdStatus(jobId);
        if (status.state == "FAILURE" || status.state == "DISCARDED")
        {
            return false;
        }
        return true;
    }

}

Может ли кто-нибудь увидеть, где я ошибаюсь?

Благодарность


person level_zebra    schedule 19.11.2015    source источник


Ответы (1)


Ваша сага должна простаивать. Вы поддерживаете его с помощью цикла while. Сообщение об истечении времени ожидания приходит в какой-то момент, и тогда вы должны проверить, что должно произойти. Либо другая касса, либо MarkAsComplete.

Я написал это в Блокноте, поэтому он может не скомпилироваться. Но это для того, чтобы иметь представление.

public class MonitorSubmissionFeedSagaData: IContainSagaData
{
public Guid Id { get; set; }
public string Originator { get; set; }
public string OriginalMessageId { get; set; }

[Unique]
public string JobId { get; set; }
public DateTime SagaStartTimeUtc { get; set; }
}

public class MonitorSubmissionFeedSaga : Saga<MonitorSubmissionFeedSagaData>,
    IAmStartedByMessages<MonitorFeedSubmissonCommand>,
    IHandleTimeouts<VerifyApiTimeOut>
{
public IEmpathyBrokerClientApi PostFileService { get; set; }

public void Handle(MonitorFeedSubmissonCommand message)
{
    Data.JobId = message.JobId;
    Data.SagaStartTimeUtc = DateTime.NowUtc;

    CreateTimeoutRequest();
}

public void CreateTimeoutRequest()
{
    RequestTimeout<VerifyApiTimeOut>(TimeSpan.FromSeconds(30));
}

public void Timeout(VerifyApiTimeOut state)
{
    if (!GetJobStatus(Data.JobId) && DateTime.NowUtc < Data.SagaStartTimeUtc.AddMinutes(60))
    {
      CreateTimeoutRequest();
    }

    MarkAsComplete();
}

bool GetJobStatus(string jobId)
{
    return false;
    var status = PostFileService.GetJobIdStatus(jobId);
    if (status.state == "FAILURE" || status.state == "DISCARDED")
    {
        return false;
    }
    return true;
}

}

Другой комментарий может заключаться в том, что сама Сага не должна обращаться к внешним службам. Желательно даже не в какую-то базу данных. Делегируйте это другому сервису. Каждые 30 секунд отправлять сообщение другому обработчику. Этот обработчик должен вызывать WebService/WebAPI. Когда он сможет подтвердить, что все правильно, ответьте на исходную сагу. Когда это неправильно, просто позвольте этому быть. Saga будет отправлять сообщения каждые 30 секунд, чтобы повторить попытку.

Через 60 минут Saga перестанет отправлять сообщения и пометить как выполненное.

person Dennis van der Stelt    schedule 20.11.2015