Task.Delay останавливает программу с непрерывным циклом через день или два - PullRequest
0 голосов
/ 06 сентября 2018

У меня есть .NET webAPI, в котором я постоянно выполняю метод Task в цикле (пока приложение не запущено).

Я использую await Task.Delay(120000) перед вызовом следующей задачи LoopMethod. API работает непрерывно хорошо в течение 1 или 2 дней, а затем останавливается в точке, где последний оператор файла журнала говорит, log.Debug("Before Task Delay..");

Это означает, что в какой-то момент задание await Task.Delay(120000); никогда не завершится.

Что-то мне не хватает?

Вот пример формата сниппета, который я использую

Я использую рекурсию, потому что следующий параметр LoopMethod зависит от возвращаемого значения предыдущего LoopMethod.

public async Task<HttpStatusCode> LoopMethod(string token) 
{
    var responseHttpStatusCode = HttpStatusCode.Unused;

   string NextToken =  await DoSomething();

    log.Debug("Before Task Delay..");
    await Task.Delay(120000);
    log.Debug("After Task Delay..");

    await LoopMethod(NextToken); 

    return responseHttpStatusCode;
}

1 Ответ

0 голосов
/ 06 сентября 2018

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

Однако мои паучьи чувства говорят мне, что это на стороне клиента, а у вас просто не хватает стека, что, в свою очередь, вызывает StackOverflowException

Наиболее распространенной причиной переполнения стека является слишком глубокая или бесконечная рекурсия, в которой функция вызывает себя так много раз что пространство необходимо для хранения переменных и информации с каждым вызовом связано больше, чем умещается в стеке.

Если вам действительно нужно это сделать, рассмотрите просто цикл while

public async Task<HttpStatusCode> LoopMethod() 
{

    while(true)
    {
       ...

       await Task.Delay(120000);

       if(condition)
          //break or return

       ...
      }
}

Или, как предлагает Джон Ву , просто используйте таймер с состоянием

если это веб-сервер, рассмотрите возможность использования службы для опроса, которая предназначена для сохранения, а не повторного использования

Обновлено из комментариев

От Кевина Госса

Хотя я согласен, что здесь нет смысла использовать рекурсию, учтите, что здесь нет настоящей рекурсии Из-за асинхронности / ожидания и того факта что Task.Delay никогда не завершится синхронно, каждое продолжение имеет свой собственный стек вызовов, и использование стека на самом деле не растет. Вы можете убедить себя, зарегистрировав значение Environment.StackTrace в начале метода. Тем не менее, вы все еще создаете задачи в каждая итерация, так что в какой-то момент вам не хватит памяти

...