using System;
using System.Collections.Concurrent;
public sealed record ErrorState(
int ErrorCount,
DateTime LastError,
DateTime SkipUntil);
public sealed class ErrorTracker
{
private readonly ConcurrentDictionary<string, ErrorState> _errors = new();
public bool ShouldSkip(string id)
{
return _errors.TryGetValue(id, out var state) && state.SkipUntil > DateTime.UtcNow;
}
public void RegisterError(string id)
{
_errors.AddOrUpdate(
id,
_ => CreateState(1),
(_, existing) => CreateState(existing.ErrorCount + 1));
}
public void RegisterSuccess(string id)
{
_errors.TryRemove(id, out _);
}
public ErrorState? GetState(string id)
{
return _errors.TryGetValue(id, out var state) ? state : null;
}
private static ErrorState CreateState(int errorCount)
{
var now = DateTime.UtcNow;
var backoff = errorCount switch
{
1 => TimeSpan.FromMinutes(5),
2 => TimeSpan.FromMinutes(30),
3 => TimeSpan.FromHours(2),
_ => TimeSpan.FromHours(24)
};
return new ErrorState(
ErrorCount: errorCount,
LastError: now,
SkipUntil: now.Add(backoff));
}
}Usage example
if (errorTracker.ShouldSkip(item.Id))
{
Console.WriteLine($"Item {item.Id} wordt overgeslagen.");
return;
}
try
{
await SynchronizeAsync(item);
errorTracker.RegisterSuccess(item.Id);
}
catch (Exception ex)
{
errorTracker.RegisterError(item.Id);
var state = errorTracker.GetState(item.Id);
Console.WriteLine(
$"Synchronisatie mislukt voor {item.Id}. " +
$"Aantal fouten: {state?.ErrorCount}, " +
$"Opnieuw proberen na: {state?.SkipUntil:u}");
}1023200cookie-checkC# ErrorTracker