Что предпочтительнее в цикле while метода RunAsync в Сервисе: использовать IsCancellationRequested или генерировать исключение

Почему пример RunAsync для нового кода Service Fabric имеет такую ​​структуру

protected override async Task RunAsync(CancellationToken cancellationToken)
{
  while(true)
  {
    cancellationToken.ThrowIfCancellationRequested();

    await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
  }
} 

вместо этого

protected override async Task RunAsync(CancellationToken cancellationToken)
{
  while(cancellationToken.IsCancellationRequested)
  {
    await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
  }
} 

Не предпочтительнее ли вариант без броска? В документах указано, что обе реализации верны: «Система будет ждать завершения вашей задачи (путем успешного завершения, отмены или ошибки)».


person Michiel Overeem    schedule 30.05.2016    source источник
comment
Я еще не очень хорошо знаком с Service Fabric, но ожидаемая семантика установки CancellationToken заключается в том, чтобы выдать OperationCanceledException если отмена была отменена и вернуть если отмена была слишком поздно . Возможно, у них просто есть этот код для согласованности, или возможно, что Service Fabric изменит способ самовосстановления в зависимости от того, как завершается RunAsync.   -  person Stephen Cleary    schedule 30.05.2016
comment
Да, именно поэтому мы изменили пример кода, чтобы создать исключение OperationCanceledException, когда непрерывный цикл в RunAsync прерывается Service Fabric, сигнализируя маркер отмены, потому что цикл RunAsync отменяется, и это ожидаемая семантика. Другие типы исключений обрабатываются по-разному для самовосстановления, сообщая системе об ошибке.   -  person Vaclav Turecek    schedule 02.06.2016


Ответы (3)


Краткий ответ - оба в порядке. Я бы использовал ThrowIfCancellationRequested, потому что ИМО это более безопасный вариант. Это также более последовательно — методы ниже в цепочке вызовов могут распространять отмену через исключение.

При возникновении исключения в RunAsync Service Fabric отправляет отчет временная ошибка (это означает, что служба перезапускается без повторного создания экземпляра/реплики).

Это обеспечивает специальную обработку для OperationCanceledException - если он был выброшен токеном отмены, переданным методу, то метод считается успешно отмененным, и об ошибке не сообщается.

Вы можете попробовать это сами, отслеживая события Microsoft-ServiceFabric-Services ETW.

person Eli Arbel    schedule 31.05.2016

cancelToken.ThrowIfCancellationRequested();

равно

если (token.IsCancellationRequested) выдать новое исключение OperationCanceledException (токен);

Обычно люди используют это как механизм управления, чтобы гарантировать, что текущая обработка будет прервана без возможного запуска какого-либо дополнительного кода. Также нет необходимости проверять отмену при вызове ThrowIfCancellationRequested().

person MalithaRukshan    schedule 16.09.2018

Это еще проще и тоже работает:

protected override async Task RunAsync(CancellationToken cancellationToken)
{
    while(true)
    {
        await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
    }
}

or

protected override async Task RunAsync(CancellationToken cancellationToken)
{
    while(cancellationToken.IsCancellationRequested)
    {
        await Task.Delay(TimeSpan.FromSeconds(1));
    }
}

Я узнал об этом, так как мой код был смоделирован по образцу кода, подобного этому:

protected override async Task RunAsync(CancellationToken cancellationToken)     
{
    var pipeline = ...
    pipeline.Start();

    while (true) {
        if (cancellationToken.IsCancellationRequested) {
            ServiceEventSource.Current.ServiceMessage(Context, "Stopping pipeline");
            await pipeline.ShutdownAsync();
        }

        cancellationToken.ThrowIfCancellationRequested();

        await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
    }
}

и трубопровод никогда не останавливался. Решение состояло в том, чтобы не использовать cancellationToken в вызове Task.Delay.

person Glorfindel    schedule 30.09.2020