Skip to content

Deploy and recover

This guide describes the production boundary supported by the current pre-release. It does not imply that public package-release tooling is available.

Use PostgreSQL and one provider configuration

Section titled “Use PostgreSQL and one provider configuration”

Use UsePostgreSql for a distributed deployment. Configure a stable schema, table prefix, tenancy mode, and worker identity before production data exists:

builder.Services
.AddEventLoom()
.UsePostgreSql(builder.Configuration.GetConnectionString("EventStore")!)
.UseMultiTenancy<AuthenticatedTenantAccessor>()
.ConfigureEventStore(options =>
{
options.Schema = "eventloom";
options.TablePrefix = "eventloom_";
})
.AddEvent<OrderPlaced>();

EventLoom generates a unique identity for each projection and outbox worker process by default (machine name, process ID, and a random suffix). Override InstanceId only when your deployment provides an equally unique and stable process identity. Do not change event names, aggregate type names, stream-ID formats, schema names, or table prefixes after writing production data without an explicit data migration.

EventLoom currently ships the model but not EventLoom-owned migrations. Build and review migrations for the dedicated EventStoreDbContext in your host application, then apply them as a deployment step before rolling out application instances.

Do not use EnsureCreatedAsync in a production database that is or will be managed with migrations. Keep the event-store migration history separate from the application’s normal EF Core context.

The PostgreSQL provider retries transient failures, serialization failures, and deadlocks according to MaxRetryAttempts (default 5). A retry runs the full append transaction again. Provide a stable AppendId for a command that can be retried after an ambiguous client-visible failure.

Expected-version and unique-constraint conflicts are business-visible. Reload the aggregate, reassess the command, and decide whether a new command is appropriate. Never blindly retry a command whose original business condition may no longer hold.

When tenancy is required:

  • Resolve tenants from a trusted authentication, authorization, or routing boundary.
  • Scope ITenantAccessor to the request or worker operation.
  • Include the tenant in application logs and correlation metadata.
  • Keep append IDs unique per tenant and command.
  • Use explicit tenant APIs only for authenticated administrative or background workflows.

EventLoom enforces matching scoped and explicit tenant values, but it cannot decide whether your application correctly authenticated the tenant.

Back up the EventLoom PostgreSQL schema together with the application data that depends on it. Event rows are immutable facts; do not update or delete them with ad hoc SQL. Monitor database availability, append latency, lock waits, retry rates, failed command responses, and storage growth.

Use EventStoreSchema.ValidateAsync(context) as a read-only deployment gate for EventLoom tables, columns, nullability, and provider-reported CLR types. The EF Core model also specifies portable keys, required fields, unique constraints, and worker query indexes for generated migrations. SQLite’s flexible type system does not expose stable CLR type metadata, so its validation remains limited to portable table, column, and nullability checks. AddEventLoomHealthChecks() registers connectivity, schema compatibility, projection, and outbox readiness checks; see Observability. EventLoom runs registered projections and persists their checkpoints and failures; inspect and repair them through ProjectionAdministration. Register an IOutboxPublisher for external integration and use its stable message ID as the transport idempotency key. See Outbox and application integration for the delivery and shared-transaction boundaries.

Treat an unhealthy projection check as an operational incident: inspect its explicit tenant-scoped failure records, correct the handler or dependency, then resume the paused projection. Skipping an event intentionally creates a read-model gap and must be an authorized, audited decision. Replay resets only the checkpoint, so production rebuilds should normally use a new projection version and a new or shadow read-model table.

For a degraded outbox check, inspect the tenant-scoped backlog and delivery attempt history. Fix publisher connectivity or destination behavior before allowing retries to drain the backlog. Downstream consumers must deduplicate using the stable outbox message ID because delivery is at least once.

Expose projection resume, skip, replay, outbox inspection, and health details only to authorized operational administrators. Never expose event payloads, metadata headers, or tenant-scoped operational records through an unauthenticated endpoint.

MapEventLoomAdminDiagnostics("EventLoomOperators") is an opt-in ASP.NET Core surface for protected, aggregate-only schema and worker diagnostics. It is not mapped by default and rejects an empty authorization-policy name. It does not map tenant-scoped inspection or repair actions; authorize and audit those application-specific workflows at your own administrative boundary.