Skip to content

Fast.EventBus

Public members, parameters, returns, and exceptions

Targets: net8.0;net9.0;net10.0.

Contract and constraints

An in-process bounded channel, not a durable or distributed message broker. AddEventBus() registers singleton publishing, dynamic subscriptions, discovered IEventSubscriber implementations and a background consumer. Default capacity is 3000. Subscriber methods return Task and take EventHandlerExecutingContext. The HTTP 202 example acknowledges enqueueing, not completed processing. PublishDelayAsync uses milliseconds and is not a persistent scheduler. EventSubscribeAttribute defaults to NumRetries=0, RetryTimeout=1000, Order=0 and GCCollect=false. Retries can repeat side effects; handlers need their own idempotency. Multiple handlers may run concurrently, and Order is not a transactional serialization guarantee. Pending work can be lost when the process exits.

Installation and examples

Install the package

bash
dotnet add package Fast.EventBus

Example 1

csharp
using Fast.EventBus;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEventBus();
var app = builder.Build();
app.MapPost("/notices", async (Notice notice, IEventPublisher publisher, CancellationToken cancellationToken) =>
{
    await publisher.PublishAsync("notice.received", notice, cancellationToken);
    return Results.Accepted();
});
app.Run();

public sealed record Notice(string Message);

public sealed class NoticeSubscriber : IEventSubscriber
{
    [EventSubscribe("notice.received")]
    public Task ReceiveAsync(EventHandlerExecutingContext context)
    {
        if (context.Source.Payload is Notice notice)
        {
            Console.WriteLine(notice.Message);
        }
        return Task.CompletedTask;
    }
}

Web-host examples belong in a consumer project using Microsoft.NET.Sdk.Web and a supported .NET target. IaaS examples can be used in an ordinary class library. Registration precedes builder.Build(); configure middleware and endpoints before app.Run(). Samples retain their original code and comments. No host, external service, database operation or client generator was run, and these snippets have not been compiled in this update.

Source reference

Nested publication and bounded backpressure

Ordinary publishers wait when the bounded queue is full. A handler publishing recursively to its own queue enqueues immediately when capacity exists; a full queue throws InvalidOperationException rather than waiting for itself. The implementation does not use an unbounded queue, drop events silently, or start detached tasks. Publish after the current handler completes or explicitly handle capacity failure.

Automatic scanning accepts only closed, concrete implementations. Explicit monitor registration takes precedence; multiple discovered monitors require an explicit choice.