Class RegistrationOutcome

Namespace
Cratis.Chronicle.Registrations
Assembly
Cratis.Chronicle.dll

Represents what became of the client's declared artifacts when RegisterAll() ran.

public record RegistrationOutcome : IEquatable<RegistrationOutcome>
Inheritance
RegistrationOutcome
Implements
Inherited Members
Extension Methods

Remarks

This exists so that a consumer holding an IEventStore can tell three states apart that used to look identical from outside: every artifact registered, some subset registered and the rest were dropped, and registration has not run yet. A read model that cannot be built is isolated and logged rather than thrown, which is right - one unbuildable read model must not cost the whole read side - but it turns a loud total failure into a quiet partial one. This is the read-only seam for asking about it afterwards; it is not a failure policy, and nothing here decides whether a failed artifact should abort start-up, fail a spec, or be tolerated. That is the consumer's call.

What it covers. Projection artifacts - both the fluent IProjectionFor<TReadModel> implementations and the model-bound read models. Those are the artifacts whose registration round-trips to the kernel inside RegisterAll(), so an outcome for them is something the client can actually observe rather than assume. IsRegistered means the client built a definition for the artifact and the kernel accepted the batch it travelled in; the registration operation itself returns no per-definition verdict, so a finer-grained claim than that would be invented. For newly registered active projections, success also means the kernel subscribed their observers in the event store's existing namespaces. It does not mean an event appended afterwards is already reflected in materialized read models. For read-your-writes, use WaitForCompletion(IAppendResultForObserverCompletion, TimeSpan?) on the append result before reading, or use a passive read model.

What it deliberately does not cover: reactors and reducers. Their Register() only opens a duplex stream - it marks itself registered and returns before any round trip to the kernel has happened. Reporting them here would mean reporting a hope as a fact, so they are left out rather than represented optimistically. A consumer that needs to know a reactor or reducer is live should wait on its observer state instead (ReactorWaitExtensions.WaitTillSubscribed, ReducerWaitExtensions.WaitTillActive), which is answered by the kernel.

Do not reach for IsConnected instead of this. It looks like it carries a registration verdict and it partly does - ConnectionLifecycle.Connected() rolls it back to false and rethrows when one of the connected handlers failed, and RegisterAll() is one of those handlers. But it is set to true before the handlers run, and only rolled back after they have all finished, so polling it races: it reads true while registration is still in flight and while a registration that is about to be reported as failed is still running. It answers "connected", which is necessary and not sufficient. Use Registration and its IsRegistering flag instead.

Constructors

RegistrationOutcome(RegistrationOutcome)

protected RegistrationOutcome(RegistrationOutcome original)

Parameters

original RegistrationOutcome

RegistrationOutcome(bool, IImmutableList<ArtifactRegistration>, Exception?)

Represents what became of the client's declared artifacts when RegisterAll() ran.

public RegistrationOutcome(bool HasRun, IImmutableList<ArtifactRegistration> Artifacts, Exception? Failure = null)

Parameters

HasRun bool

Whether RegisterAll() has finished at least once, successfully or not.

Artifacts IImmutableList<ArtifactRegistration>

The declared artifacts, each carrying whether it registered and, if not, the failure that stopped it.

Failure Exception

The Exception that stopped RegisterAll() itself, or null when it finished. This is not the same as an artifact that failed to build: those are isolated and reported in Artifacts, and registration carries on. This one ended the run.

Remarks

This exists so that a consumer holding an IEventStore can tell three states apart that used to look identical from outside: every artifact registered, some subset registered and the rest were dropped, and registration has not run yet. A read model that cannot be built is isolated and logged rather than thrown, which is right - one unbuildable read model must not cost the whole read side - but it turns a loud total failure into a quiet partial one. This is the read-only seam for asking about it afterwards; it is not a failure policy, and nothing here decides whether a failed artifact should abort start-up, fail a spec, or be tolerated. That is the consumer's call.

What it covers. Projection artifacts - both the fluent IProjectionFor<TReadModel> implementations and the model-bound read models. Those are the artifacts whose registration round-trips to the kernel inside RegisterAll(), so an outcome for them is something the client can actually observe rather than assume. IsRegistered means the client built a definition for the artifact and the kernel accepted the batch it travelled in; the registration operation itself returns no per-definition verdict, so a finer-grained claim than that would be invented. For newly registered active projections, success also means the kernel subscribed their observers in the event store's existing namespaces. It does not mean an event appended afterwards is already reflected in materialized read models. For read-your-writes, use WaitForCompletion(IAppendResultForObserverCompletion, TimeSpan?) on the append result before reading, or use a passive read model.

What it deliberately does not cover: reactors and reducers. Their Register() only opens a duplex stream - it marks itself registered and returns before any round trip to the kernel has happened. Reporting them here would mean reporting a hope as a fact, so they are left out rather than represented optimistically. A consumer that needs to know a reactor or reducer is live should wait on its observer state instead (ReactorWaitExtensions.WaitTillSubscribed, ReducerWaitExtensions.WaitTillActive), which is answered by the kernel.

Do not reach for IsConnected instead of this. It looks like it carries a registration verdict and it partly does - ConnectionLifecycle.Connected() rolls it back to false and rethrows when one of the connected handlers failed, and RegisterAll() is one of those handlers. But it is set to true before the handlers run, and only rolled back after they have all finished, so polling it races: it reads true while registration is still in flight and while a registration that is about to be reported as failed is still running. It answers "connected", which is necessary and not sufficient. Use Registration and its IsRegistering flag instead.

Fields

NotRun

The outcome for an event store whose RegisterAll() has not finished yet.

public static readonly RegistrationOutcome NotRun

Field Value

RegistrationOutcome

Remarks

Registration is wired to the connection lifecycle, so "not yet" and "never" look the same from outside - this value covers both. It does not cover "tried and failed": a run that throws still reports itself, carrying its Failure. Use RegistrationWaitExtensions.WaitForRegistration to wait for whichever arrives.

Properties

Artifacts

The declared artifacts, each carrying whether it registered and, if not, the failure that stopped it.

public IImmutableList<ArtifactRegistration> Artifacts { get; init; }

Property Value

IImmutableList<ArtifactRegistration>

EqualityContract

protected virtual Type EqualityContract { get; }

Property Value

Type

Failure

The Exception that stopped RegisterAll() itself, or null when it finished. This is not the same as an artifact that failed to build: those are isolated and reported in Artifacts, and registration carries on. This one ended the run.

public Exception? Failure { get; init; }

Property Value

Exception

Failures

Gets the declared artifacts that did not register, each carrying the failure that stopped it.

public IEnumerable<ArtifactRegistration> Failures { get; }

Property Value

IEnumerable<ArtifactRegistration>

HasRun

Whether RegisterAll() has finished at least once, successfully or not.

public bool HasRun { get; init; }

Property Value

bool

IdentityDrift

Gets the likely identity changes detected before this registration run, retained across background retries. These are heuristic findings, not per-artifact registration failures. Only reactor and event type findings prevent registration under the Fail policy.

public IImmutableList<ArtifactIdentityDrift> IdentityDrift { get; init; }

Property Value

IImmutableList<ArtifactIdentityDrift>

IsRegistering

Gets a value indicating whether a registration run is in flight, or a reconnect will re-register after a disconnect. The other members describe the previous run while this is true.

public bool IsRegistering { get; init; }

Property Value

bool

IsSuccess

Gets a value indicating whether registration ran, finished, and every declared artifact registered.

public bool IsSuccess { get; }

Property Value

bool

Methods

Deconstruct(out bool, out IImmutableList<ArtifactRegistration>, out Exception?)

public void Deconstruct(out bool HasRun, out IImmutableList<ArtifactRegistration> Artifacts, out Exception? Failure)

Parameters

HasRun bool
Artifacts IImmutableList<ArtifactRegistration>
Failure Exception

Equals(RegistrationOutcome?)

Compare with another RegistrationOutcome by value.

public virtual bool Equals(RegistrationOutcome? other)

Parameters

other RegistrationOutcome

The outcome to compare with.

Returns

bool

True if the outcomes carry the same artifacts, false otherwise.

Remarks

The generated record equality would compare Artifacts with the list's own equality, which is by reference - so two outcomes carrying the same artifacts came out unequal, and a record's headline promise did not hold for the one member that matters. It ships a NotRun sentinel that invites being compared against, so this is not theoretical.

Equals(object?)

public override bool Equals(object? obj)

Parameters

obj object

Returns

bool

GetHashCode()

public override int GetHashCode()

Returns

int

PrintMembers(StringBuilder)

protected virtual bool PrintMembers(StringBuilder builder)

Parameters

builder StringBuilder

Returns

bool

ToString()

public override string ToString()

Returns

string

Operators

operator ==(RegistrationOutcome?, RegistrationOutcome?)

public static bool operator ==(RegistrationOutcome? left, RegistrationOutcome? right)

Parameters

left RegistrationOutcome
right RegistrationOutcome

Returns

bool

operator !=(RegistrationOutcome?, RegistrationOutcome?)

public static bool operator !=(RegistrationOutcome? left, RegistrationOutcome? right)

Parameters

left RegistrationOutcome
right RegistrationOutcome

Returns

bool