Codebelt
v10.5.5

Cuemon.Resilience

Delegate-based transient fault handling for sync and async operations with explicit retry, latency, and detection rules.

.NET 10.0 / .NET 9.0 / .NET Standard 2.0 MIT 44,782 downloads

Overview

Cuemon.Resilience wraps existing delegates in a retry loop that stays close to the call site. Instead of introducing a policy registry or host-level integration, you pass the work you already have plus a small options callback that decides what counts as a transient failure, how many attempts to allow, and how long to wait between retries.

The package centers on the static TransientOperation entry points for synchronous and asynchronous delegates. When retries are exhausted the operation ends in an AggregateException, and when measured latency grows beyond the configured ceiling it stops with a LatencyException, giving repeatable work a small but explicit resilience boundary.

Key APIs

TransientOperation.WithFunc<TResult> executes a return-producing delegate inside the retry loop and yields the first successful result. Its overload family also accepts up to five delegate arguments, so existing method groups can be wrapped without rewriting them as closures.

TransientOperation.WithAction applies the same recovery model to delegates that do not return a value. Use it when the operation is idempotent but the observable outcome is completion rather than a returned result.

TransientOperation.WithFuncAsync<TResult> extends the same contract to Task<TResult> delegates and forwards a CancellationToken from AsyncTransientOperationOptions. It is the async entry point for I/O-bound work that should keep retry and cancellation rules together.

TransientOperation.WithActionAsync retries Task-returning delegates with the same detection, backoff, and latency checks used by the synchronous APIs. The package handles the recovery wait asynchronously so the retry loop fits naturally around async method groups.

TransientOperationOptions defines the retry policy. DetectionStrategy, RetryStrategy, RetryAttempts, EnableRecovery, and MaximumAllowedLatency control whether an exception is treated as transient, how long the next wait should be, and when latency becomes a hard stop.

AsyncTransientOperationOptions inherits the same retry settings and adds CancellationToken for asynchronous delegates. That keeps async configuration aligned with the synchronous options object instead of creating a separate policy model.

TransientOperation.FaultCallback exposes a static hook that runs when a transient retry cycle reaches its limit. The callback receives fault evidence built from the invoked method and runtime arguments, which makes it useful for diagnostics and failure reporting.

LatencyException represents an operation whose measured latency exceeded MaximumAllowedLatency. Tests also verify that it serializes cleanly, so callers can preserve the failure detail when the exception crosses boundaries.

Basic usage

using System;
using System.Net.Http;
using Codebelt.Extensions.Xunit;
using Cuemon.Resilience;
using Xunit;

namespace MyProject.Tests;

public class InventoryProbeTest : Test
{
    public InventoryProbeTest(ITestOutputHelper output) : base(output)
    {
    }

    [Fact]
    public void ShouldRetryInventoryProbe_WhenGatewayTimeoutIsTransient()
    {
        var attempts = 0;

        var status = TransientOperation.WithFunc(
            () =>
            {
                attempts++;
                if (attempts == 1) { throw new HttpRequestException("Gateway timeout."); }
                return "inventory-ready";
            },
            options =>
            {
                options.DetectionStrategy = ex => ex is HttpRequestException;
                options.RetryAttempts = 2;
                options.RetryStrategy = _ => TimeSpan.Zero;
            });

        TestOutput.WriteLine($"Inventory probe recovered after {attempts} attempts.");
        Assert.Equal("inventory-ready", status);
        Assert.Equal(2, attempts);
    }
}

Use this pattern when you need to retry an idempotent delegate that is expected to fail briefly for reasons such as network instability or temporary upstream unavailability.

It matters because the retry rules stay explicit at the call site while the success path still returns the same value the original delegate would have produced.

Installation

dotnet add package Cuemon.Resilience

Usage guidance

Use this package when you need delegate-based retry handling with explicit transient detection, configurable backoff, and latency ceilings around work that is safe to repeat. If the operation must fail immediately, is not safe to rerun, or already has its own recovery boundary, keep the plain framework call instead of wrapping it in TransientOperation.

Family packages