Задача не переходит в ошибочное состояние, если для ConfigurAwait установлено значение False
Вот что я пытаюсь достичь. Я запускаю задачу и не делаю ожидания / результата. Чтобы убедиться, что если запущенная задача перейдет в состояние сбоя (например, сгенерировать исключение), я завершу процесс, вызвав Environment FailFast в Continuation.
Как проблема, с которой я сталкиваюсь, заключается в том, что если я запускаю ниже кода, Inside ContinueWith, состояние задачи (которая вызвала исключение) отображается как "RanToCompletion". Я ожидал, что это будет ошибочное состояние.
private Task KickOfTaskWorkAsync()
{
var createdTask = Task.Run(() => this.RunTestTaskAsync(CancellationToken.None).ConfigureAwait(false), CancellationToken.None);
createdTask.ContinueWith(
task => Console.WriteLine("Task State In Continue with => {0}", task.Status));
return createdTask;
}
private async Task RunTestTaskAsync(CancellationToken cancellationToken)
{
throw new Exception("CrashingRoutine: Crashing by Design");
}
Это действительно странно:(Если я удаляю "ConfigureAwait(false)" из вызова функции Task.Run, задача переходит в состояние Failed внутри Продолжить с. Действительно в растерянности, чтобы объяснить, что происходит, и была бы признательна за помощь сообщества.
[Обновление]: Мой коллега указал на очевидную ошибку. Я использую ConfigureAwait, в то время как я делаю вызов RunTestAsync внутри Test.Run, хотя я не жду этого. В этом случае ConfigureAwait не возвращает задачу в Task.Run. Если я не вызываю ConfigureAwait, Задача возвращается, и все работает как положено.
1 ответ
Ваша ошибка является конкретным примером более широкой категории ошибок: вы не наблюдаете Task
вы на самом деле заботитесь.
В вашем примере кода RunTestTaskAsync()
возвращает Task
объект. Завершается синхронно (потому что нет await
), Итак Task
объект, который он возвращает, уже сбился при возврате метода из-за исключения. Ваш код тогда звонит ConfigureAwait()
на этом вина Task
объект.
Но все это происходит внутри другого Task
то есть тот, который вы запускаете при звонке Task.Run()
, это Task
ничего не делает, чтобы соблюсти исключение, поэтому оно завершается нормально.
Причина, по которой вы наблюдаете исключение при удалении ConfigureAwait()
Вызов не имеет ничего общего с самим вызовом. Если вы оставили вызов и прошли true
вместо этого вы все равно не заметите исключение. Причина, по которой вы можете наблюдать исключение при удалении вызова, заключается в том, что без вызова ConfigureAwait()
возвращаемое значение лямбда-выражения Task
и это вызывает другую перегрузкуTask.Run()
,
Эта перегрузка немного отличается от других. Из документации:
Поставляет в очередь указанную работу для запуска в пуле потоков и возвращает прокси для задачи, возвращаемой функцией.
То есть пока начинается новый Task
, Task
объект, который он возвращает, представляет не Task
, но тот, который возвращается вашим лямбда-выражением. И этот прокси принимает то же состояние, что и Task
это оборачивает, так что вы видите это в Faulted
государство.
Исходя из кода, который вы разместили, я бы сказал, что вам не следует звонить Task.Run()
на первом месте. Следующее будет работать так же хорошо, без издержек и усложнения прокси:
static void Main(string[] args)
{
Task createdTask = RunTestTaskAsync();
createdTask.ConfigureAwait(false);
createdTask.ContinueWith(
task => Console.WriteLine("Task State In Continue with => {0}", task.Status)).Wait();
}
private static async Task RunTestTaskAsync()
{
throw new Exception("CrashingRoutine: Crashing by Design");
}
(Я удалил CancellationToken
ценности, потому что они не имеют никакого отношения к вашему вопросу и здесь совершенно излишни.)