Files
jobtrackingapp/JobTrackerApi/Services/EmailSendAttemptRecoveryHostedService.cs
T
cesnimda ee5ef7e12a fix(email): reconcile abandoned sends
Age stale pre-delivery attempts to failed and in-delivery attempts to uncertain without provider I/O. Notify each owner with content-free guidance and keep recovery idempotent across replicas and restarts.
2026-08-10 00:16:56 +02:00

45 lines
1.6 KiB
C#

namespace JobTrackerApi.Services;
public sealed class EmailSendAttemptRecoveryHostedService(
IServiceScopeFactory scopes,
IStartupReadiness startupReadiness,
ILogger<EmailSendAttemptRecoveryHostedService> logger) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await startupReadiness.WaitUntilReadyAsync(stoppingToken);
while (!stoppingToken.IsCancellationRequested)
{
try
{
await using var scope = scopes.CreateAsyncScope();
var result = await scope.ServiceProvider.GetRequiredService<EmailSendAttemptStore>()
.ReconcileAbandonedAsync(stoppingToken);
if (result.FailedPending > 0 || result.UncertainSending > 0)
{
logger.LogWarning(
"Recovered abandoned email attempts: failedPending={FailedPending}, uncertainSending={UncertainSending}. No provider retry was attempted.",
result.FailedPending, result.UncertainSending);
}
}
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
{
break;
}
catch (Exception ex)
{
logger.LogError(ex, "Email send-attempt recovery failed; provider delivery was not attempted.");
}
try
{
await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
}
catch (OperationCanceledException)
{
break;
}
}
}
}