当 API returns "too many requests" 错误时,在 C# 中多次重试同一任务
Retry the same task multiple times in C# when API returns "too many requests" error
我有一个在同步上下文中通过重试执行异步任务的通用方法。
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 语句中,所以它肯定不会被处理掉。第一次上传尝试后的流位置会不会有问题?
- 重试同一个Task对象是否正常?我应该改变我做事的方式吗?
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
将不会触发重新执行。它将简化 return 值或异常。
因此,您必须为每次重试尝试创建一个新任务。为此,您可以在 RunWithRetries
中预期 Func<Task<T>>
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); });
我有一个在同步上下文中通过重试执行异步任务的通用方法。
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 语句中,所以它肯定不会被处理掉。第一次上传尝试后的流位置会不会有问题?
- 重试同一个Task对象是否正常?我应该改变我做事的方式吗?
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
将不会触发重新执行。它将简化 return 值或异常。
因此,您必须为每次重试尝试创建一个新任务。为此,您可以在 RunWithRetries
Func<Task<T>>
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); });