Skip to content

Latest commit

 

History

31 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ReliableWebhooks

CI Release NuGet .NET 10 License: MIT

English | Português (Brasil)

ReliableWebhooks is a .NET 10 library for reliable outbound webhook delivery. It provides explicit primitives for durable enqueueing, lease-based dispatch, bounded concurrency, HTTP delivery, retry classification and scheduling, HMAC-SHA256 signing, observability, and Microsoft dependency injection/hosting.

Use it when an HTTP POST is not enough: deliveries must survive failures, coordinate multiple workers, retry deterministically, and expose operational state without pretending that exactly-once HTTP delivery exists.

Guarantees and boundaries

  • With a conforming durable IWebhookDeliveryStore, the intended delivery model is at-least-once.
  • ReliableWebhooks does not guarantee exactly-once delivery. Receivers must be idempotent and tolerate duplicates.
  • The core package does not ship a production durable store. Durability across process restarts depends on the store supplied and configured by the consuming application.
  • InMemoryWebhookDeliveryStore is process-local, not durable, and intended only for tests, samples, and local development.
  • One IWebhookDeliveryTransport.SendAsync call represents one HTTP attempt; retry timing is handled separately by the retry policy and dispatcher.
  • Automatic dead-letter replay, receiver-side idempotency, and secret-rotation policy remain application responsibilities.

For the complete production contract and operational guidance, see Production usage and the Persistence contract.

Installation

The package targets net10.0:

dotnet add package ReliableWebhooks --version 1.0.0

or:

<PackageReference Include="ReliableWebhooks" Version="1.0.0" />

Quick start

This minimal example uses the in-memory store so it can run without external infrastructure. Replace it with a conforming durable IWebhookDeliveryStore before using ReliableWebhooks in production.

using System.Text.Json;
using ReliableWebhooks;

byte[] payload = JsonSerializer.SerializeToUtf8Bytes(new
{
    OrderId = 123,
    Status = "created",
});

var message = new WebhookMessage(
    id: Guid.NewGuid().ToString("N"),
    eventType: "order.created",
    destination: new Uri("https://example.com/webhooks"),
    payload: payload,
    contentType: "application/json");

IWebhookDeliveryStore store = new InstrumentedWebhookDeliveryStore(
    new InMemoryWebhookDeliveryStore());

await store.EnqueueAsync(message, DateTimeOffset.UtcNow);

using var handler = new HttpClientHandler
{
    AllowAutoRedirect = false,
    UseCookies = false,
};

using var httpClient = new HttpClient(handler);
IWebhookDeliveryTransport transport = new WebhookHttpTransport(httpClient);
IWebhookRetryPolicy retryPolicy = new DefaultWebhookRetryPolicy();

var dispatcher = new WebhookDispatcher(
    store,
    transport,
    retryPolicy,
    new WebhookDispatcherOptions
    {
        MaxConcurrency = 4,
        LeaseDuration = TimeSpan.FromMinutes(1),
        PollInterval = TimeSpan.FromSeconds(1),
        ShutdownGracePeriod = TimeSpan.FromSeconds(5),
    });

using var stop = new CancellationTokenSource(TimeSpan.FromSeconds(10));
await dispatcher.RunAsync(stop.Token);

AddHostedDispatcher() is opt-in. Applications can instead resolve and run WebhookDispatcher directly when they need to own its lifecycle.

A runnable end-to-end application with signing, success, retries, dead-letter behavior, and diagnostics is available in samples/ReliableWebhooks.Sample.

Delivery flow

  1. Create a WebhookMessage with a stable ID, event type, destination, exact payload bytes, content type, and optional headers.
  2. Enqueue it through IWebhookEnqueueService or the lower-level IWebhookDeliveryStore.
  3. WebhookDispatcher claims only due work up to its available concurrency and receives expiring leases.
  4. WebhookHttpTransport performs one request attempt and returns a transport-neutral result.
  5. Success and permanent failure become terminal states; retryable failures are scheduled by IWebhookRetryPolicy.
  6. A conforming durable store persists the resulting state so expired or abandoned work can be reclaimed safely.

Stable IDs make enqueueing idempotent at the store boundary, while leases prevent stale workers from overwriting the current owner. These mechanisms support at-least-once delivery; they do not remove the need for receiver idempotency.

Minimal production registration

A production application owns the persistence adapter and explicitly registers it:

services.AddSingleton<IWebhookDeliveryStore, MyDurableWebhookStore>();

ReliableWebhooksBuilder webhooks = services.AddReliableWebhooks();
webhooks.AddHostedDispatcher();

The store must implement the durability, atomic claim, lease, stale-owner rejection, retry scheduling, and terminal-state semantics defined by the persistence contract.

Read next

  • Production usage: docs/production-usage.md — DI/hosting, retry and response classification, signing and receiver verification, destination security, observability, configuration, tuning, and troubleshooting.
  • Persistence contract: docs/persistence.md — durable state, idempotent enqueue, atomic claims, leases, ownership, transitions, and conformance testing.
  • Runnable sample: samples/ReliableWebhooks.Sample — end-to-end integration using the public API.
  • v1.0.0 scope: docs/release-v1.0.0.md — release boundaries, distribution, and supported surface.
  • Security policy: SECURITY.md — supported security reporting process and project security guidance.

Extensibility

The core behaviors are exposed through replaceable abstractions, including persistence, delivery transport, response classification, retry policy/jitter, request signing and secret resolution, destination policy, request-header resolution, dispatcher timing, and observability integration. The production guide documents the built-in defaults and the boundaries that custom implementations must preserve.

Contributing

See CONTRIBUTING.md for local development, validation, and contribution guidance.

License

ReliableWebhooks is licensed under the MIT License.

About

Reliable outbound webhook delivery for .NET 10 with retries, leasing, HMAC signing, observability, secure HTTP defaults, and pluggable durable persistence.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages