我有一个通用方法可以在同步上下文中通过重试执行异步任务。
public static T RunWithRetries<T>(Task<T> task)
{
while(...) // 3 attempts
{
try
{
task.GetAwaiter().GetResult();
}
catch
{
// sleep & retry later in case of some exceptions, for example 429
}
}
}
然后我从异步 API 传递任何方法来运行它。
SyncHelper.RunWithRetries(externalAPI.UploadAsync(fileRequest, fileStream));
问题是除非在请求期间发生异常并且我们需要重试,否则它可以正常工作。如果发生错误,所有后续重试也会抛出相同的异常。所以,我的问题是
- 发生这种情况是因为 fileStream 对象吗?它在 using 语句中,所以它肯定不会被处理掉。第一次上传尝试后的流位置会不会有问题?
- 重试同一个任务对象是否正常?我是否应该改变我做这件事的方式来做更好的事情?
最佳答案
Is this happening because of the
fileStream
object? It's in the using statement, so it's not being disposed for sure. Can the stream position after first upload attempt be a problem?
是的,这是您的问题之一。每当读取流时,它的 Position
不会自动重置为 0。如果您尝试重新读取它,那么它不会读取任何内容,因为该位置位于流的末尾。
因此,您必须每次都创建一个新流,或者 rewind the stream to the beginning .
Is it normal that the same Task object is being retried? Should I change the way I'm doing it to something better?
每当任务完成时(有特定结果或异常),然后重新 await
-ing 或检索其 Result
不会触发重新执行。它将简单地返回值或异常。
因此,您必须为每次重试尝试创建一个新任务。为此,您可以预期 Func<Task<T>>
在你的RunWithRetries
public static T RunWithRetries<T>(Func<Task<T>> issueRequest)
{
...
issueRequest().GetAwaiter().GetResult();
}
从调用方来看,它看起来像这样:
RunWithRetries(() => externalAPI.UploadAsync(fileRequest, new FileStream(...)));
//or
RunWithRetries(() => { fileStream.Position = 0; externalAPI.UploadAsync(fileRequest, fileStream); });
关于c# - 当 API 返回 "too many requests"错误时,在 C# 中多次重试同一任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70122701/