Retry transient HTTP errors with a handler

C#
using System;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

/// <summary>Retries idempotent requests on 429, 5xx or network errors.</summary>
public sealed class RetryHandler : DelegatingHandler
{
    private const int MaxAttempts = 4;

    public RetryHandler(HttpMessageHandler inner) : base(inner) { }
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        for (var attempt = 1; ; attempt++)
        {
            try
            {
                var response = await base.SendAsync(request, cancellationToken);
                if (!ShouldRetry(response.StatusCode) || attempt == MaxAttempts)
                {
                    return response;
                }
                response.Dispose();
            }
            catch (HttpRequestException) when (attempt < MaxAttempts)
            {
                // Network error: fall through to the backoff below.
            }

            var delay = TimeSpan.FromMilliseconds(200 * Math.Pow(2, attempt - 1));
            await Task.Delay(delay, cancellationToken);
        }
    }

    private static bool ShouldRetry(HttpStatusCode code) =>
        code == HttpStatusCode.TooManyRequests || (int)code >= 500;
}