fix: handle Nextcloud CalDAV 429 rate limiting with Polly retry
Replaces hand-rolled retry logic with Microsoft.Extensions.Http.Resilience (Polly v8). The named 'nextcloud' HttpClient retries up to 3 times on 429 with exponential backoff (2s, 4s, 8s). Also adds a 300ms delay after every individual PUT/DELETE request to reduce burst rate. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c4c67e2b73
commit
0520ce3847
3 changed files with 21 additions and 7 deletions
|
|
@ -1,6 +1,9 @@
|
|||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authentication.Google;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.Extensions.Http.Resilience;
|
||||
using Polly;
|
||||
using System.Net;
|
||||
using System.Security.Claims;
|
||||
using ShiftScheduler.Services;
|
||||
using ShiftScheduler.Shared;
|
||||
|
|
@ -24,6 +27,18 @@ builder.Services.AddSingleton(authorizedEmails);
|
|||
builder.Services.AddSingleton<IConfigurationService>(new ConfigurationService(appConfiguration));
|
||||
builder.Services.AddMemoryCache();
|
||||
builder.Services.AddHttpClient<TransportApiService>();
|
||||
builder.Services.AddHttpClient("nextcloud")
|
||||
.AddResilienceHandler("nextcloud-retry", pipeline =>
|
||||
{
|
||||
pipeline.AddRetry(new HttpRetryStrategyOptions
|
||||
{
|
||||
MaxRetryAttempts = 3,
|
||||
Delay = TimeSpan.FromSeconds(2),
|
||||
BackoffType = DelayBackoffType.Exponential,
|
||||
ShouldHandle = args => ValueTask.FromResult(
|
||||
args.Outcome.Result?.StatusCode == HttpStatusCode.TooManyRequests)
|
||||
});
|
||||
});
|
||||
builder.Services.AddSingleton<IcsExportService>();
|
||||
builder.Services.AddSingleton<PdfExportService>();
|
||||
builder.Services.AddSingleton<ITransportApiService, TransportApiService>();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="9.0.8" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ public class NextcloudCalendarService(
|
|||
reportRequest.Headers.Add("Depth", "1");
|
||||
reportRequest.Content = new StringContent(body, Encoding.UTF8, "application/xml");
|
||||
|
||||
var client = httpClientFactory.CreateClient();
|
||||
var client = httpClientFactory.CreateClient("nextcloud");
|
||||
var reportResponse = await client.SendAsync(reportRequest);
|
||||
reportResponse.EnsureSuccessStatusCode();
|
||||
|
||||
|
|
@ -126,8 +126,7 @@ public class NextcloudCalendarService(
|
|||
deleteResponse.StatusCode != System.Net.HttpStatusCode.NotFound)
|
||||
deleteResponse.EnsureSuccessStatusCode();
|
||||
|
||||
if (eventUrls.Count > 1)
|
||||
await Task.Delay(200);
|
||||
await Task.Delay(300);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +154,7 @@ public class NextcloudCalendarService(
|
|||
|
||||
private async Task CreateShiftEventsAsync(string calendarId, List<ShiftWithTransport> shifts)
|
||||
{
|
||||
var client = httpClientFactory.CreateClient();
|
||||
var client = httpClientFactory.CreateClient("nextcloud");
|
||||
|
||||
foreach (var shiftWithTransport in shifts)
|
||||
{
|
||||
|
|
@ -176,6 +175,7 @@ public class NextcloudCalendarService(
|
|||
var putRequest = CreateRequest(HttpMethod.Put, $"{calendarId}{Uri.EscapeDataString(uid)}.ics");
|
||||
putRequest.Content = new StringContent(icsContent, Encoding.UTF8, "text/calendar");
|
||||
(await client.SendAsync(putRequest)).EnsureSuccessStatusCode();
|
||||
await Task.Delay(300);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(shift.AfternoonTime))
|
||||
|
|
@ -189,10 +189,8 @@ public class NextcloudCalendarService(
|
|||
var putRequest = CreateRequest(HttpMethod.Put, $"{calendarId}{Uri.EscapeDataString(uid)}.ics");
|
||||
putRequest.Content = new StringContent(icsContent, Encoding.UTF8, "text/calendar");
|
||||
(await client.SendAsync(putRequest)).EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
if (shifts.Count > 1)
|
||||
await Task.Delay(300);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue