A minimalist, dependency-free retry and timeout utility for C#. Provides type-safe retry policies with configurable delays, exponential backoff, timeout support, and exception filtering.
$ dotnet add package Fox.RetryKitA minimalist, dependency-free retry and timeout utility for C#. Build resilient applications with simple, type-safe retry policies.
dotnet add package Fox.RetryKit
using Fox.RetryKit;
// Retry up to 3 times
var policy = RetryPolicy.Retry(3);
policy.Execute(() =>
{
CallUnstableService();
});
// Retry 3 times with 500ms delay
var policy = RetryPolicy.Retry(3, TimeSpan.FromMilliseconds(500));
await policy.ExecuteAsync(async () =>
{
await CallUnstableApiAsync();
});
// Retry 5 times with exponential backoff (100ms, 200ms, 400ms, 800ms, 1600ms)
var policy = RetryPolicy.ExponentialBackoff(5, TimeSpan.FromMilliseconds(100));
var result = await policy.ExecuteAsync(async () =>
{
return await FetchDataAsync();
});
// Combine retry, delay, timeout, and exception filtering
var policy = RetryPolicy.Retry(3, TimeSpan.FromMilliseconds(500))
.Handle<HttpRequestException>()
.WithTimeout(TimeSpan.FromSeconds(10));
var data = await policy.ExecuteAsync(async () =>
{
return await FetchFromUnstableServiceAsync();
});
var policy = RetryPolicy.Retry(3, TimeSpan.FromMilliseconds(100))
.OnRetry((exception, attempt, delay) =>
{
Console.WriteLine($"Retry {attempt} after {delay.TotalMilliseconds}ms: {exception.Message}");
});var policy = RetryPolicy.Retry(5, TimeSpan.FromMilliseconds(200))
.WithJitter(); // Adds ±25% random variationvar policy = RetryPolicy.ExponentialBackoff(10, TimeSpan.FromMilliseconds(100))
.WithMaxDelay(TimeSpan.FromSeconds(5)); // Cap at 5 secondsvar delays = new[]
{
TimeSpan.FromMilliseconds(100),
TimeSpan.FromMilliseconds(250),
TimeSpan.FromMilliseconds(500),
TimeSpan.FromSeconds(1)
};
var policy = RetryPolicy.WaitAndRetry(delays);var policy = RetryPolicy.Retry(3, TimeSpan.FromMilliseconds(100));
// Static fallback value
var result = policy.Fallback(() => GetRemoteData(), "default-value");
// Dynamic fallback provider
var result = policy.Fallback(() => GetPrimaryData(), () => GetCachedData());var policy = RetryPolicy.Retry(5, TimeSpan.FromMilliseconds(100))
.RetryIf<HttpResponseMessage>(response => !response.IsSuccessStatusCode);var result = await policy.ExecuteWithResultAsync(async () => await FetchDataAsync());
Console.WriteLine($"Success: {result.Success}");
Console.WriteLine($"Attempts: {result.Attempts}");
Console.WriteLine($"Duration: {result.TotalDuration}");var httpPolicy = RetryPolicy.Retry(5, TimeSpan.FromMilliseconds(500))
.Handle<HttpRequestException>()
.WithTimeout(TimeSpan.FromSeconds(30));
var response = await httpPolicy.ExecuteAsync(async () =>
{
using var client = new HttpClient();
return await client.GetStringAsync("https://api.example.com/data");
});var dbPolicy = RetryPolicy.ExponentialBackoff(3, TimeSpan.FromSeconds(1))
.Handle<SqlException>()
.Handle<TimeoutException>();
await dbPolicy.ExecuteAsync(async () =>
{
await using var connection = new SqlConnection(connectionString);
await connection.OpenAsync();
});var filePolicy = RetryPolicy.Retry(3, TimeSpan.FromMilliseconds(100))
.Handle<IOException>();
var content = filePolicy.Execute(() => File.ReadAllText("config.json"));Retry(int count) - Immediate retryRetry(int count, TimeSpan delay) - Fixed delay retryExponentialBackoff(int retries, TimeSpan initialDelay) - Exponential backoffTimeout(TimeSpan duration) - Timeout constraintWaitAndRetry(IEnumerable<TimeSpan> delays) - Custom delay sequenceHandle<TException>() - Exception filteringWithTimeout(TimeSpan duration) - Add timeoutOnRetry(Action<Exception, int, TimeSpan>) - Retry callbackWithJitter() - Add ±25% random variationWithMaxDelay(TimeSpan maxDelay) - Cap maximum delayRetryIf<T>(Func<T, bool> predicate) - Conditional retryExecute(Action action) - Synchronous executionExecute<T>(Func<T> func) - Synchronous with resultExecuteAsync(Func<Task> func) - Asynchronous executionExecuteAsync<T>(Func<Task<T>> func) - Asynchronous with resultExecuteWithResult() / ExecuteWithResultAsync() - With telemetryFallback<T>() / FallbackAsync<T>() - Graceful degradationMIT License - Copyright (c) 2026 Károly Akácz
Contributions are welcome! Please open an issue or pull request in the GitHub repository.
If you like Fox.OptionKit, please give it a ⭐ on the GitHub repository!