zcbot/windows-node/Zcbot.WindowsNode/Transfers/TransferRetryPolicy.cs

61 lines
1.7 KiB
C#

using System.Net;
using System.Net.Http;
namespace Zcbot.WindowsNode;
internal enum TransferFailureKind
{
Authentication,
Transient,
Permanent,
Cancelled,
}
internal static class TransferRetryPolicy
{
private static readonly TimeSpan[] DownloadBackoff =
[
TimeSpan.FromMilliseconds(250),
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(3),
];
internal static TransferFailureKind Classify(HttpStatusCode statusCode)
{
if (statusCode is HttpStatusCode.Unauthorized or HttpStatusCode.Forbidden)
{
return TransferFailureKind.Authentication;
}
if (statusCode is HttpStatusCode.RequestTimeout
or HttpStatusCode.TooManyRequests
|| (int)statusCode >= 500)
{
return TransferFailureKind.Transient;
}
return TransferFailureKind.Permanent;
}
internal static TransferFailureKind Classify(Exception exception) => exception switch
{
OperationCanceledException => TransferFailureKind.Cancelled,
HttpRequestException or IOException => TransferFailureKind.Transient,
_ => TransferFailureKind.Permanent,
};
internal static TimeSpan? RetryDelay(
HttpMethod method,
int attempt,
HttpStatusCode? statusCode = null,
Exception? exception = null)
{
if (method != HttpMethod.Get || attempt >= DownloadBackoff.Length)
{
return null;
}
var kind = statusCode is HttpStatusCode status
? Classify(status)
: exception is not null ? Classify(exception) : TransferFailureKind.Permanent;
return kind == TransferFailureKind.Transient ? DownloadBackoff[attempt] : null;
}
}