我们正在运行一个 Web 应用程序,它有多个线程通过单例类访问 Azure 的 DocumentDB API,以读取或写入我们的 Cosmos 数据库中的数据。在这个类中,我们在静态构造函数中初始化我们的 DocumentClient。在我们的整个程序中,多个线程可以访问数据库,调用如下方法(假设 Uri 是一个全局定义的属性):
public static async Task SaveItem<T>(T item)
{
try
{
await Client.UpsertDocumentAsync(Uri, item);
}
catch (Exception)
{
// Some Basic Exception Handling.
}
}
几乎每个方法都是异步的,我们从不对这些方法的调用者调用 .Wait 或 .Result。问题是,从多个线程保存大量项目后,我们最终会得到以下异常:
System.Threading.Tasks.TaskCanceledException: A task was canceled.
这个异常特别奇怪的是,一旦第一次抛出,任何数据库调用(读取或写入)都不会成功,所有这些都会抛出相同的 TaskCancelledException。我们找到的唯一补救方法是重新启动程序。
抛出异常时的完整堆栈跟踪打印输出如下:
System.Threading.Tasks.TaskCanceledException: A task was canceled.
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Azure.Documents.GatewayStoreModel.<>c__DisplayClass10.<<InvokeAsync>b__f>d__12.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Azure.Documents.BackoffRetryUtility`1.<>c__DisplayClass2.<<ExecuteAsync>b__0>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Azure.Documents.BackoffRetryUtility`1.<ExecuteRetry>d__1b.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.Azure.Documents.BackoffRetryUtility`1.<ExecuteRetry>d__1b.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Azure.Documents.BackoffRetryUtility`1.<ExecuteAsync>d__a.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Azure.Documents.GatewayStoreModel.<InvokeAsync>d__1f.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Azure.Documents.GatewayStoreModel.<ProcessMessageAsync>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Azure.Documents.Client.DocumentClient.<ReadAsync>d__30c.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Azure.Documents.Client.DocumentClient.<ReadDocumentPrivateAsync>d__18d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Azure.Documents.BackoffRetryUtility`1.<>c__DisplayClass2.<<ExecuteAsync>b__0>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Azure.Documents.BackoffRetryUtility`1.<ExecuteRetry>d__1b.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.Azure.Documents.BackoffRetryUtility`1.<ExecuteRetry>d__1b.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Azure.Documents.BackoffRetryUtility`1.<ExecuteAsync>d__a.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
at AutomatedRegressionTestSuite.Managers.DatabaseManager.<GetItemAsync>d__20`1.MoveNext() in C:\Users\Administrator\Perforce\WinBuildServer\tools\Asriel\AutomatedRegressionTestSuite\Managers\DatabaseManager.cs:line 451
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at AutomatedRegressionTestSuite.Managers.DatabaseManager.<GetItemById>d__8`1.MoveNext() in C:\Users\Administrator\Perforce\WinBuildServer\tools\Asriel\AutomatedRegressionTestSuite\Managers\DatabaseManager.cs:line 104
--- End of inner exception stack trace ---
我们如何防止这些任务取消的异常发生,或者至少以一种方式处理它们,以便我们的整个数据库在抛出一个异常后仍然可以访问?
最佳答案
TaskCanceledException 来自 httpclient,这意味着它是一个 http 超时异常。请检查客户端的负载,异常的短时负载峰值可能会导致此问题。否则,一种替代方法是在 ConnectionPolicy 中提高 requestTimeout 以给它更多时间。
关于c# - 在 C# 中避免 Azure DocumentDB 中的任务取消异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49779976/