LiteBus
Architecture

Hosted Services

LiteBus separates dependency registration from host execution through a manifest model. Modules register startup tasks, background services, and diagnostic probes on IModuleConfiguration; the generic host bridge runs them after AddLiteBus builds the manifest.

SurfaceResponsibilityPackage
IStartupTaskOne-shot host startup work (RunAsync)LiteBus.Runtime.Abstractions
IModuleConfiguration.RegisterStartupTaskManifest entry for startup tasksLiteBus.Runtime
IBackgroundServiceLong-running loop (ExecuteAsync)LiteBus.Runtime.Abstractions
IModuleConfiguration.RegisterBackgroundServiceManifest entry for background servicesLiteBus.Runtime
IDiagnosticCheckFramework-neutral readiness probeLiteBus.Runtime.Abstractions
InboxModuleBuilder.AddDiagnosticCheck / OutboxModuleBuilder.AddDiagnosticCheckApplication-facing probe registration sugarLiteBus.Inbox.Abstractions, LiteBus.Outbox.Abstractions
IModuleConfiguration.RegisterDiagnosticCheckInternal manifest entry used by module Build() implementationsLiteBus.Runtime
LiteBusHostManifestResolved manifest after module buildLiteBus.Runtime.Abstractions
Generic host bridgeMaps manifest entries to a single IHostedService orchestratorLiteBus.Runtime.Extensions.Hosting (shared), LiteBus.Runtime.Extensions.Microsoft.Hosting, LiteBus.Runtime.Extensions.Autofac.Hosting

Call services.AddLiteBus(builder => ...) using ILiteBusBuilder from LiteBus.Runtime.Composition. Register storage, dispatch, ingress, and processors inside nested AddInbox / AddOutbox builders.

Service Lifetime Constraint

Manifest-registered background services and startup tasks are composed as singleton host adapters. Microsoft DI and Autofac integrations register one IMessageDispatchScopeFactory, and processors use it to open a fresh scope for every leased envelope.

When handlers need a per-request DbContext or another scoped service, register handlers with scoped lifetime (the default from RegisterFromAssembly). MessageMediator creates a per-mediation dispatch scope through IMessageDispatchScopeFactory, so in-process SendAsync / PublishAsync calls resolve distinct scoped handler instances without manual scoping. EF stores use application-registered IDbContextFactory<TContext> instances for operation contexts. Do not inject scoped services directly into singleton processor services.

IDiagnosticCheck.Name must match the name passed to AddDiagnosticCheck<TCheck>(string name) on the inbox or outbox module builder. The health bridge validates the names at runtime.

Inbox Processor

builder.Services.AddLiteBus(builder =>
{
    builder.AddMessaging(_ => { });
    builder.AddCommands(c => c.Register<MyCommandHandler>());

    builder.AddInbox(inbox =>
    {
        inbox.Contracts.Register<MyCommand>("my.command", 1);
        inbox.UsePostgreSqlStorage(pg => pg.UseDataSource(dataSource));
        inbox.UseInProcessDispatch();
        inbox.EnableInboxProcessor(host => host.PollInterval = TimeSpan.FromSeconds(1));
    });
});

EnableInboxProcessor registers InboxProcessorBackgroundService on the manifest.

Outbox Processor

builder.Services.AddLiteBus(builder =>
{
    builder.AddMessaging(_ => { });
    builder.AddEvents(e => e.Register<OrderSubmittedEventHandler>());

    builder.AddOutbox(outbox =>
    {
        outbox.Contracts.Register<OrderSubmitted>("orders.events.submitted", 1);
        outbox.UsePostgreSqlStorage(pg => pg.UseDataSource(dataSource));
        outbox.UseInProcessDispatch();
        outbox.EnableOutboxProcessor(host => host.PollInterval = TimeSpan.FromSeconds(1));
    });
});

Registration Order Inside the Builder

Configure storage, dispatch, and processor hosting in the same builder lambda. The builder records all choices before module build, so callback order does not change the resolved durable path. Storage modules register schema initializers as IStartupTask when schema initialization is enabled. Startup tasks run sequentially before background services.

inbox.UsePostgreSqlStorage(pg => pg.UseDataSource(dataSource));
inbox.UseInProcessDispatch();
inbox.EnableInboxProcessor();

PostgreSQL Schema Bootstrap

UsePostgreSqlStorage registers PostgreSqlInboxSchemaInitializer / PostgreSqlOutboxSchemaInitializer as IStartupTask when EnableSchemaInitialization is enabled (the default).

inbox.UsePostgreSqlStorage(postgres =>
{
    postgres.UseDataSource(dataSource);
    postgres.EnsureSchemaCreationOnStartup();
});

Inbox and outbox schema version 3 and saga schema version 2 use migration-owned upgrade files. EnsureAsync creates missing current-version tables but rejects older shapes; it does not run migrations. Production deployments should apply DDL and call ValidateAsync in deploy checks. Development may use EnsureSchemaCreationOnStartup() for new databases. See PostgreSQL Schema Management.

Disable host schema work with postgres.DisableSchemaInitialization() when DDL is fully migration-owned.

AMQP Inbox Ingress

UseAmqpIngress registers TransportInboxIngressConsumer by default. Use ingress.DisableIngressConsumer() or ingress.HostOptions.Enabled = false to register the handler without a consumer loop.

Register AddAmqpTransport(connectionOptions) once at the root composition boundary. AMQP ingress and dispatch declare that module as a dependency and share its IMessageConsumer and ITransportPublisher; neither feature adapter creates broker connectivity during Build().

Manual Execution

Resolve InboxProcessorBackgroundService (or any manifest IBackgroundService) and call ExecuteAsync when you do not use the generic host. Resolve schema initializers (or any IStartupTask) and call RunAsync for manual startup work.

Diagnostics and Observability

LiteBus emits OpenTelemetry metrics from inbox, outbox, and transport paths. Register meters with AddLiteBusInboxMetrics(), AddLiteBusOutboxMetrics(), and AddLiteBusTransportMetrics() from the matching LiteBus.*.Extensions.OpenTelemetry packages. The aggregate OpenTelemetry meta-package is removed in v6.

AddLiteBus registers LiteBusHostManifest, which lists startup tasks, background services, and diagnostic probe descriptors.

Consumer-Owned Diagnostic Probes

inbox.AddDiagnosticCheck<PostgreSqlInboxSchemaDiagnosticCheck>("litebus.inbox.schema");

Implement IDiagnosticCheck in application code for schema validation, broker connectivity, or deployment-specific readiness rules.

Health Endpoint Behavior

LiteBus.Extensions.AspNetCore maps GET /litebus/health to manifest probes. LiteBusManagementOptions.FailHealthWhenNoProbes defaults to true: when the manifest has zero probes, the endpoint returns degraded/unhealthy. AddHealthChecks().AddLiteBus() uses the same default through LiteBusHealthCheckOptions.FailHealthWhenNoProbes. Set both to false in local samples so demos work without registering probes. Production templates should keep the default true and register at least one probe.

Both host surfaces expose DiagnosticChecks.Timeout and DiagnosticChecks.MaxParallelism. The Generic Host health registration carries litebus and ready tags. Broker modules register AMQP, Kafka, SQS, or Azure Service Bus readiness probes; SQS and Azure require an explicit queue or subscription diagnostic target.

Startup tasks run sequentially inside the LiteBus host orchestrator before any background service loop starts. When a startup task throws, host startup fails closed: the orchestrator does not start background services and the exception propagates from IHostedService.StartAsync.

The orchestrator derives from the .NET Generic Host BackgroundService contract and supervises every LiteBus loop. If one loop throws unexpectedly, it requests IHostApplicationLifetime.StopApplication() immediately and rethrows the failure for the host to observe. Normal shutdown cancellation is suppressed. Keep the Generic Host default BackgroundServiceExceptionBehavior.StopHost; configuring Ignore weakens fail-closed supervision for hosted services outside the LiteBus orchestrator.

See the .NET 10 HostOptions.BackgroundServiceExceptionBehavior contract for the host-level policy.

builder.Services.AddLiteBusManagement(options => options.FailHealthWhenNoProbes = false);
builder.Services.AddHealthChecks().AddLiteBus(options => options.FailHealthWhenNoProbes = false);
app.AddLiteBusManagementEndpoints();

Probe DiagnosticResult.Data is included in the JSON health response.

Operator Query APIs

IInboxManager and IOutboxManager expose GetStatusCountsAsync, filtered queries, selective requeue, purge (with confirmation guards), and dead-letter replay.

ASP.NET Core Management Endpoints

Management routes (/litebus/inbox/*, /litebus/outbox/*, /litebus/health) require authentication by default. Anonymous access is denied unless you set AllowAnonymousManagement = true (samples use this in Development only).

builder.Services.AddAuthentication().AddJwtBearer(/* ... */);
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("LiteBusOperator", policy => policy.RequireRole("operator"));
});
builder.Services.AddLiteBusManagement(options =>
{
    options.AuthorizationPolicy = "LiteBusOperator";
});

app.UseAuthentication();
app.UseAuthorization();
app.AddLiteBusManagementEndpoints();

Apply rate limits and audit logging in application code. LiteBus does not ship authentication.

Deferred Visibility

Schedule inbox accept or outbox enqueue through metadata visibility instead of separate scheduler interfaces:

await inbox.AcceptAsync(
    InboxAcceptItem<ShipOrder>.From(
        new ShipOrder(orderId),
        InboxAcceptMetadata.Immediate with
        {
            Visibility = MessageVisibility.After(TimeSpan.FromMinutes(15))
        }));

IInboxScheduler and IOutboxScheduler were removed in v6. See Migration guide v6.

Shared Contracts Through Messaging Composition

services.AddLiteBus(builder =>
{
    builder.AddMessaging(messaging =>
        messaging.Contracts.Register<OrderSubmitted>("orders.events.submitted", 1));
    builder.AddCommands(c => c.RegisterFromAssembly(typeof(MyCommandHandler).Assembly));
    builder.AddEvents(e => e.RegisterFromAssembly(typeof(OrderSubmittedEventHandler).Assembly));

    builder.AddInbox(inbox =>
    {
        inbox.UsePostgreSqlStorage(pg => pg.UseConnectionString(connectionString));
        inbox.UseInProcessDispatch();
        inbox.EnableInboxProcessor();
    });

    builder.AddOutbox(outbox =>
    {
        outbox.UsePostgreSqlStorage(pg => pg.UseConnectionString(connectionString));
        outbox.UseInProcessDispatch();
        outbox.EnableOutboxProcessor();
    });
});

Autofac hosts use the same ILiteBusBuilder overload on ContainerBuilder.AddLiteBus.

OpenTelemetry Operations Examples

SignalSuggested alert
litebus.inbox.queue.depth (tag litebus.inbox.status=Pending)Pending depth above SLO for 5 minutes
litebus.inbox.processor.loop_errorsAny sustained increase
litebus.transport.circuit_breaker.openValue 1 for more than one minute
Lease-lost / persist-rejected countersSpike after deploy or DB failover

Export through your OTLP sink (Prometheus, Azure Monitor, Datadog). Instrument names on public telemetry types are stable contract; do not rename without a major release.

See Architecture for the full metric catalog.

On this page