Table of Contents

Class OutboxMessage

Namespace
Trellis.EntityFrameworkCore
Assembly
Trellis.EntityFrameworkCore.Outbox.dll

A persisted event awaiting relay — a transactional-outbox row. Carries either a captured IDomainEvent or a translated IIntegrationEvent, distinguished by Kind.

public sealed class OutboxMessage
Inheritance
OutboxMessage
Inherited Members
Extension Methods

Remarks

For domain rows, the OutboxCaptureInterceptor writes one row per uncommitted domain event in the same SaveChangesAsync(CancellationToken) transaction as the aggregate change that raised it, so state and outbound notifications commit atomically. OutboxRelay{TContext} later drains pending rows and routes each by Kind: domain events re-dispatch to IDomainEventHandler<TEvent>s, and any integration events their translators produce are staged as new Integration rows and published through IIntegrationEventPublisher.

This is an infrastructure record, not a domain aggregate; the rows are transient and may be pruned once ProcessedAt is set. Deleting processed rows loses no source-of-truth state — the aggregate tables remain authoritative (this is an outbox, not an event store).

Properties

Attempts

Number of relay attempts so far.

public int Attempts { get; }

Property Value

int

CausationId

The direct predecessor: inbound message id on a domain row, domain row id on a translation.

public Guid? CausationId { get; }

Property Value

Guid?

CompletedHandlers

For Domain rows, the FullName of every IDomainEventHandler<TEvent> that has already completed for this event. A retry skips these, so a handler that succeeded on an earlier attempt is never invoked twice because an unrelated sibling failed. Empty for integration rows, which have a single publish step rather than a fan-out.

public IReadOnlyList<string> CompletedHandlers { get; }

Property Value

IReadOnlyList<string>

Remarks

Deliberately not cleared by IOutboxMaintenance.ReplayAsync: replaying a parked message means "finish the work that did not happen", so the handlers that already ran must stay skipped. It is also not cleared by MarkProcessed(DateTimeOffset), so a processed row still shows which handlers ran, for forensics.

CorrelationId

The optional application-owned business workflow identifier.

public string? CorrelationId { get; }

Property Value

string

EventType

The assembly-qualified name of the concrete event type, used to rehydrate the payload.

public string EventType { get; }

Property Value

string

Id

Stable message identity (UUIDv7) for consumer-side idempotency / de-duplication.

public Guid Id { get; }

Property Value

Guid

Kind

Whether this row carries a domain event or a translated integration event.

public OutboxMessageKind Kind { get; }

Property Value

OutboxMessageKind

LastError

The most recent relay error, if any.

public string? LastError { get; }

Property Value

string

LockedBy

The claim token of the relay drain that currently holds this row; null when unclaimed.

public Guid? LockedBy { get; }

Property Value

Guid?

LockedUntil

The UTC instant until which this row is not eligible for draining; null when eligible now. It serves two roles: while a drain is publishing the row it is the exclusive claim (lease) expiry, so concurrent relay instances (horizontal scale-out) never publish the same row twice and a crashed instance's rows become reclaimable once the lease expires; after a failed attempt it is the retry time (an exponential backoff), so a failing message is retried with growing spacing rather than in a tight loop.

public DateTime? LockedUntil { get; }

Property Value

DateTime?

MessageSource

The optional producer namespace, supplied by the application.

public string? MessageSource { get; }

Property Value

string

OccurredAt

When the event occurred, copied from the event's OccurredAt.

public DateTimeOffset OccurredAt { get; }

Property Value

DateTimeOffset

Payload

The JSON-serialized event.

public string Payload { get; }

Property Value

string

ProcessedAt

When the message was successfully relayed; null while pending.

public DateTimeOffset? ProcessedAt { get; }

Property Value

DateTimeOffset?

Sequence

Database-generated monotonic insertion order; the relay processes ascending.

public long Sequence { get; }

Property Value

long

TraceParent

The W3C traceparent captured in the producing transaction.

public string? TraceParent { get; }

Property Value

string

TraceState

The W3C tracestate captured in the producing transaction.

public string? TraceState { get; }

Property Value

string