Task.WhenAny не существует, когда задача завершена - PullRequest
0 голосов
/ 30 марта 2020

У нас есть логика c, чтобы фоновое задание продолжалось, или каждые 20 минут, или когда задание завершалось.

Упрощенная версия того, что я хочу сделать, выглядит следующим образом:

Задача для контроля, если нам нужно выйти:

private static TaskCompletionSource<bool> forceSyncTask = new TaskCompletionSource<bool>();

Фоновое задание:

     Task.Factory.StartNew(
                async () =>
                {
                    do
                    {
                        await Dosomething();
                        await Task.WhenAny(Task.Delay(TimeSpan.FromMinutes(20)), forceSyncTask.Task);

                        // Always reset the force sync property
                        forceSyncTask = new TaskCompletionSource<bool>();
                    }
                    while (true);
                });

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

    if (!forceSyncTask.Task.IsCompleted)
    {
        forceSyncTask.TrySetResult(true);
    }

Я проверил его в dev box, и он работает. Однако после того, как я развернул его на нашем веб-сервисе в среде prod, даже если я успешно установил SetResult (я должен войти в систему, чтобы узнать, возвращает ли TrySetResult значение true или нет), Task.WhenAny не завершается, как ожидалось.

У любого есть любой идея почему?

1 Ответ

1 голос
/ 31 марта 2020

Во-первых, я рекомендую вам использовать установленное решение для приостановки асинхронных методов, таких как PauseToken Стивена Туба или PauseToken из моей библиотеки AsyncEx . В коде присутствуют некоторые красные флаги: StartNew с делегатом async и без TaskScheduler и TaskCompletionSource<T> без опции RunContinuationsAsynchronously. Лучше придерживаться конструкций более высокого уровня (Task.Run и PauseToken, соответственно), потому что на конструкциях низкого уровня много острых углов.

Что касается именно проблемы, это трудно сказать, тем более что вы (и мы) не можем воспроизвести это локально. Вот мои главные догадки:

  1. Вы столкнулись с проблемой, вызванной тем фактом, что продолжения выполняются синхронно, если это возможно - то есть TrySetResult заканчивается прямым вызовом некоторого кода внутри Task.WhenAny.
  2. Вы испытываете исчерпание потока на своем рабочем сервере.
...