エラーが待ちタイムアウト後Task.Waitで二回投げされている。この問題は、私はTask.Waitを使用していたという事実から生じているようだC#/タスクエラーが待ちタイムアウト後Task.Waitで2回記録されている
タイムアウト。問題は、タスクタイムアウトが2回記録された後にスローされた例外か、タイムアウトが記録されないうちにスローされたエラーのいずれかです。私はコードを追加し、シナリオをよりよく理解するために使ったテストを行いました。
このテストの背後にあるアイデアは、例外がスローされる(3秒で)前に、(2秒で)タイムアウトが強制されるということです。このような状況で例外はどうなりますか?以下はその結果です。 「ブーム」例外は決して報告されない。これは、タスクでは観察されない例外として残っています。
[MassUpdateEngine.cs]
// Package the collection of statements that need to be run as a Task.
// The Task can then be given a cancellation token and a timeout.
Task task = Task.Run(async() =>
{
try
{
Thread.Sleep(3000);
throw new Exception("boom");
// Checking whether the task was cancelled at each step in the task gives us finer grained control over when we should bail out.
token.ThrowIfCancellationRequested();
Guid id = SubmitPreview();
results.JobId = id;
token.ThrowIfCancellationRequested();
bool previewStatus = await GetPreviewStatus(id, token);
Logger.Log("Preview status: " + previewStatus);
token.ThrowIfCancellationRequested();
ExecuteUpdate(id);
token.ThrowIfCancellationRequested();
bool updateStatus = await GetUpdateStatus(id, token);
Logger.Log("Update status: " + updateStatus);
token.ThrowIfCancellationRequested();
string value = GetUpdateResults(id);
results.NewValue = value;
}
// It appears that awaited methods will throw exceptions on when cancelled.
catch (OperationCanceledException)
{
Logger.Log("***An operation was cancelled.***");
}
}, token);
task.ContinueWith(antecedent =>
{
//Logger.Log(antecedent.Exception.ToString());
throw new CustomException();
}, TaskContinuationOptions.OnlyOnFaulted);
[Program.cs]
try
{
MassUpdateEngine engine = new MassUpdateEngine();
// This call simulates calling the MassUpdate.Execute method that will handle preview + update all in one "synchronous" call.
//Results results = engine.Execute();
// This call simulates calling the MassUpdate.Execute method that will handle preview + update all in one "synchronous" call along with a timeout value.
// Note: PreviewProcessor and UpdateProcessor both sleep for 3 seconds each. The timeout needs to be > 6 seconds for the call to complete successfully.
int timeout = 2000;
Results results = engine.Execute(timeout);
Logger.Log("Results: " + results.NewValue);
}
catch (TimeoutException ex)
{
Logger.Log("***Timeout occurred.***");
}
catch (AggregateException ex)
{
Logger.Log("***Aggregate exception occurred.***\n" + ex.ToString());
}
catch (CustomException ex)
{
Logger.Log("A custom exception was caught and handled.\n" + ex.ToString());
}
例外が発生していないため、適切に記録されていないため、これは機能しません。
この情報は、次のルールにつながる:
- が.ContinueWithから投げないでください。ここからスローされた例外は、呼び出しスレッドにマーシャリングされません。これらの例外は、観察されない例外として残され、効果的に食べられる。
- タスクからの例外は、タイムアウトで待機を使用しているときに、呼び出し元のスレッドにマーシャリングされる場合もあれば、マーシャリングされない場合もあります。 Wait呼び出しのタイムアウトの前に例外が発生した場合、例外は呼び出しスレッドにマーシャリングされます。 Waitコールのタイムアウト後に例外が発生した場合、例外はタスクの監視されていない例外のままです。
ルール2はかなり醜いです。このシナリオでは、例外を確実にログに記録するにはどうすればよいですか? .ContinueWith/OnlyOnFaultedを使用して例外を記録することができます(下記参照)。
task.ContinueWith(antecedent =>
{
Logger.Log(antecedent.Exception.ToString());
//throw new CustomException();
}, TaskContinuationOptions.OnlyOnFaulted);
例外が待機コールのタイムアウトの前に発生する場合は、その例外は呼び出し元のスレッドにマーシャリングされ、グローバルな未処理の例外ハンドラによって処理(及びログイン)し、その後に渡されますれます.ContinueWithタスク(およびログに記録される)は、同じ例外に対して2つのエラーログエントリを生成します。
私はここで欠けているものがなければなりません。どんな助けもありがとう。