Skip to content

Generated Code

The IdempotencyModule declaration generates effect methods and DI registration.

What Gets Generated

Given:

[EffectsModule(typeof(IIdempotencyStore))]
[ServiceRegistration(nameof(AddDefaultIdempotency))]
public static partial class IdempotencyModule
{
    public static void AddDefaultIdempotency(this IServiceCollection services)
    {
        services.TryAddSingleton<IIdempotencyStore, InMemoryIdempotencyStore>();
    }
}

Effect Methods

public static partial class IdempotencyModule
{
    public static partial class Idempotency
    {
        public static Eff<RT, bool> TryClaimAsync<RT>(string key, TimeSpan? expiry = null)
            where RT : IHasIdempotencyStore => ...

        public static Eff<RT, bool> IsClaimedAsync<RT>(string key)
            where RT : IHasIdempotencyStore => ...

        public static Eff<RT, Unit> ReleaseAsync<RT>(string key)
            where RT : IHasIdempotencyStore => ...

        public static Eff<RT, CachedResponse?> TryGetCachedResponseAsync<RT>(string key)
            where RT : IHasIdempotencyStore => ...

        public static Eff<RT, Unit> StoreCachedResponseAsync<RT>(
            string key, CachedResponse response, TimeSpan? expiry = null)
            where RT : IHasIdempotencyStore => ...
    }
}

Capability Interface

public interface IHasIdempotencyStore
{
    IIdempotencyStore IdempotencyStore { get; }
}

CachedResponse

public sealed record CachedResponse(int StatusCode, Dictionary<string, string> Headers, byte[] Body);

Captures the full HTTP response (status, headers, body) for replay on duplicate requests.

DI Registration

TryAddSingleton means production stores (Redis, database) registered first take priority. InMemoryIdempotencyStore uses ConcurrentDictionary with TTL-based expiry.

Using Without Effects

public class WebhookProcessor(IIdempotencyStore store)
{
    public async Task ProcessAsync(string eventId, string payload)
    {
        if (!await store.TryClaimAsync(eventId, TimeSpan.FromHours(24)))
            return; // Already processed

        // Process the webhook...
    }
}

For functional composition, see Effects Composition.