Class UnitOfWork
- Namespace
- Cratis.Chronicle.Transactions
- Assembly
- Cratis.Chronicle.dll
Represents an implementation of IUnitOfWork.
public class UnitOfWork : IUnitOfWork, IDisposable
- Inheritance
-
UnitOfWork
- Implements
- Inherited Members
- Extension Methods
Constructors
UnitOfWork(CorrelationId, Action<IUnitOfWork>, IEventStore, UnitOfWorkLifecyclePolicy, ILogger<UnitOfWork>?)
Initializes a unit of work with the given lifecycle policy.
public UnitOfWork(CorrelationId correlationId, Action<IUnitOfWork> onCompleted, IEventStore eventStore, UnitOfWorkLifecyclePolicy lifecyclePolicy, ILogger<UnitOfWork>? logger = null)
Parameters
correlationIdCorrelationIdThe correlation identifier.
onCompletedAction<IUnitOfWork>Called on completion.
eventStoreIEventStoreThe event store.
lifecyclePolicyUnitOfWorkLifecyclePolicyThe lifecycle policy.
loggerILogger<UnitOfWork>Optional logger for late staging diagnostics.
UnitOfWork(CorrelationId, Action<IUnitOfWork>, IEventStore, IActivitySource<UnitOfWork>?)
Initializes a unit of work with compatibility staging behavior.
public UnitOfWork(CorrelationId correlationId, Action<IUnitOfWork> onCompleted, IEventStore eventStore, IActivitySource<UnitOfWork>? activitySource = null)
Parameters
correlationIdCorrelationIdThe correlation identifier.
onCompletedAction<IUnitOfWork>Called on completion.
eventStoreIEventStoreThe event store.
activitySourceIActivitySource<UnitOfWork>Optional activity source for tracing.
UnitOfWork(CorrelationId, Action<IUnitOfWork>, IEventStore, IActivitySource<UnitOfWork>?, UnitOfWorkLifecyclePolicy, ILogger<UnitOfWork>?)
Initializes a new instance of the UnitOfWork class.
public UnitOfWork(CorrelationId correlationId, Action<IUnitOfWork> onCompleted, IEventStore eventStore, IActivitySource<UnitOfWork>? activitySource, UnitOfWorkLifecyclePolicy lifecyclePolicy, ILogger<UnitOfWork>? logger = null)
Parameters
correlationIdCorrelationIdThe correlation identifier.
onCompletedAction<IUnitOfWork>Called on completion.
eventStoreIEventStoreThe event store.
activitySourceIActivitySource<UnitOfWork>Optional activity source for tracing.
lifecyclePolicyUnitOfWorkLifecyclePolicyThe policy for staging after completion begins.
loggerILogger<UnitOfWork>Optional logger for late staging diagnostics.
Properties
CorrelationId
Gets the CorrelationId for the IUnitOfWork.
public CorrelationId CorrelationId { get; }
Property Value
EffectReceipt
Gets the winning receipt after a successful receipted commit.
public EffectReceiptResult? EffectReceipt { get; }
Property Value
HasEnrolledDecisionReads
Gets a value indicating whether a decision read has ever been successfully enrolled in this unit of work.
public bool HasEnrolledDecisionReads { get; }
Property Value
Remarks
Once true, the value remains true after commit, rollback, or disposal. Custom implementations that do not override this property report false by default.
IsCompleted
Gets the value indicating whether the unit of work is completed.
public bool IsCompleted { get; }
Property Value
Remarks
Unit of work being completed is semantically equal to it being disposed.
IsEnforcingReadProtection
Gets whether this unit permanently uses enforced read protection and a strict lifecycle.
public bool IsEnforcingReadProtection { get; }
Property Value
IsSuccess
Gets a value indicating whether the IUnitOfWork was successful.
public bool IsSuccess { get; }
Property Value
Methods
AddDecisionRead(IDecisionRead)
Enroll a protected read as a commit dependency.
public void AddDecisionRead(IDecisionRead read)
Parameters
readIDecisionReadThe protected read.
Exceptions
- UnitOfWorkDecisionReadsNotSupported
This implementation does not support decision reads.
AddEnrollmentContributor(IUnitOfWorkEnrollmentContributor)
Attaches a contributor for the lifetime of an enrollment scope, such as one command invocation.
public IDisposable AddEnrollmentContributor(IUnitOfWorkEnrollmentContributor contributor)
Parameters
contributorIUnitOfWorkEnrollmentContributorThe contributor to consult before enrollment.
Returns
- IDisposable
A handle that removes only this registration on disposal.
Exceptions
- UnitOfWorkEnrollmentContributorsNotSupported
The implementation does not support contributors.
- UnitOfWorkMutatedDuringEnrollment
A contributor attempted to change registrations.
AddEvent(EventSequenceId, EventSourceId, object, Causation, EventStreamType?, EventStreamId?, EventSourceType?, ConcurrencyScope?, IEnumerable<string>?, DateTimeOffset?, Subject?)
Add an event that has occurred to the IUnitOfWork.
public void AddEvent(EventSequenceId eventSequenceId, EventSourceId eventSourceId, object @event, Causation causation, EventStreamType? eventStreamType = null, EventStreamId? eventStreamId = null, EventSourceType? eventSourceType = null, ConcurrencyScope? concurrencyScope = null, IEnumerable<string>? tags = null, DateTimeOffset? occurred = null, Subject? subject = null)
Parameters
eventSequenceIdEventSequenceIdThe EventSequenceId for the event.
eventSourceIdEventSourceIdThe EventSourceId for the event.
eventobjectThe event that has occurred.
causationCausationThe Causation for the event.
eventStreamTypeEventStreamTypeOptional EventStreamType for the event, will default to the All stream if not set.
eventStreamIdEventStreamIdOptional EventStreamId for the event, will default to Default is not set.
eventSourceTypeEventSourceTypeOptional EventSourceType for the event, will default to Default is not set.
concurrencyScopeConcurrencyScopeOptional ConcurrencyScope for the event, will default to NotSet if not set.
tagsIEnumerable<string>Optional dynamic tags to associate with the event.
occurredDateTimeOffset?Optional timestamp for when the event occurred.
subjectSubjectOptional subject identifying what the event is about.
AddEventWithNamedTags(EventSequenceId, EventSourceId, object, IEnumerable<NamedTag>, Causation, EventStreamType?, EventStreamId?, EventSourceType?, ConcurrencyScope?, IEnumerable<string>?, DateTimeOffset?, Subject?)
Add an event with structured named tags.
public void AddEventWithNamedTags(EventSequenceId eventSequenceId, EventSourceId eventSourceId, object @event, IEnumerable<NamedTag> namedTags, Causation causation, EventStreamType? eventStreamType = null, EventStreamId? eventStreamId = null, EventSourceType? eventSourceType = null, ConcurrencyScope? concurrencyScope = null, IEnumerable<string>? tags = null, DateTimeOffset? occurred = null, Subject? subject = null)
Parameters
eventSequenceIdEventSequenceIdThe event sequence.
eventSourceIdEventSourceIdThe event source.
eventobjectThe event.
namedTagsIEnumerable<NamedTag>Structured named tags.
causationCausationThe causation.
eventStreamTypeEventStreamTypeOptional stream type.
eventStreamIdEventStreamIdOptional stream id.
eventSourceTypeEventSourceTypeOptional source type.
concurrencyScopeConcurrencyScopeOptional concurrency scope.
tagsIEnumerable<string>Optional plain tags.
occurredDateTimeOffset?Optional occurred time.
subjectSubjectOptional subject.
Exceptions
- UnitOfWorkNamedTagsNotSupported
The implementation cannot carry nonempty named tags.
AddEventWithOptions(EventSequenceId, EventSourceId, object, Causation, EventEnrollmentOptions)
Enrolls an event with its scope origin. Alternate implementations retain their existing enrollment behavior.
public void AddEventWithOptions(EventSequenceId eventSequenceId, EventSourceId eventSourceId, object @event, Causation causation, EventEnrollmentOptions options)
Parameters
eventSequenceIdEventSequenceIdThe event sequence.
eventSourceIdEventSourceIdThe event source.
eventobjectThe event.
causationCausationThe causation.
optionsEventEnrollmentOptionsThe enrollment options.
Exceptions
- ConcurrencyScopeOriginNotValidForEvents
The origin is reserved for reads.
AddEvents(EventSequenceId, IEnumerable<EventForEventSourceId>, IEnumerable<KeyValuePair<EventSourceId, ConcurrencyScope>>)
Adds an ordered batch of events and independently labeled concurrency scopes to the IUnitOfWork.
public void AddEvents(EventSequenceId eventSequenceId, IEnumerable<EventForEventSourceId> events, IEnumerable<KeyValuePair<EventSourceId, ConcurrencyScope>> concurrencyScopes)
Parameters
eventSequenceIdEventSequenceIdThe EventSequenceId for the events.
eventsIEnumerable<EventForEventSourceId>The events to add, in commit order.
concurrencyScopesIEnumerable<KeyValuePair<EventSourceId, ConcurrencyScope>>The concurrency scopes to validate with the batch.
Remarks
Both inputs are materialized before this method returns. Consecutive single-event enrollments retain their legacy source-grouped order. Each call to this method forms a globally ordered segment between those legacy segments, and commit flattens every segment into one append operation. A concurrency-scope key can be an independent label when its scope does not narrow by event-source ID. For event-target labels, a missing or NotSet scope retains the configured strategy. An independent non-target label must use a concrete exact scope or None.
Exceptions
- ConcurrencyScopeLabelMustBeSpecified
Thrown when an event target or scope label is unspecified, blank, or whitespace.
- ConcurrencyScopeEventSourceIdDoesNotMatchLabel
Thrown when a scope narrows by an event source different from its label.
- DuplicateConcurrencyScopeForEventSourceId
Thrown when more than one scope has the same label in one enrollment.
- ConflictingConcurrencyScopesForLabel
Thrown when a label already has a different explicit scope in this unit of work.
- IndependentConcurrencyScopeMustBeExplicit
Thrown when an independent non-target label does not have a concrete exact scope or None.
- UnitOfWorkCannotSpanEventSequences
Thrown when this unit of work is already bound to another event sequence.
- UnitOfWorkBatchEnrollmentNotSupported
Thrown when an alternate unit-of-work implementation does not support ordered batch enrollment.
AddEvents(EventSequenceId, IEnumerable<EventForEventSourceId>, IEnumerable<KeyValuePair<EventSourceId, ConcurrencyScope>>, ConcurrencyScopeOrigin)
Enrolls an ordered batch with the origin of its supplied scopes.
public void AddEvents(EventSequenceId eventSequenceId, IEnumerable<EventForEventSourceId> events, IEnumerable<KeyValuePair<EventSourceId, ConcurrencyScope>> concurrencyScopes, ConcurrencyScopeOrigin origin)
Parameters
eventSequenceIdEventSequenceIdThe event sequence.
eventsIEnumerable<EventForEventSourceId>The ordered events.
concurrencyScopesIEnumerable<KeyValuePair<EventSourceId, ConcurrencyScope>>The supplied scopes.
originConcurrencyScopeOriginThe scope contribution.
Exceptions
- ConcurrencyScopeOriginNotValidForEvents
The origin is reserved for reads.
AllowReads(ReadAllowance, string)
Allows explicit reads without permitting immediate appends or removing existing dependencies.
public IDisposable AllowReads(ReadAllowance allowance, string reason)
Parameters
allowanceReadAllowanceAdvisory reads or reads contributed before exposure.
reasonstringThe explicit reason for the region.
Returns
- IDisposable
The flow-local read region.
Exceptions
- UnitOfWorkReadProtectionNotSupported
The implementation cannot support allowances.
- ReadProtectionAllowanceNotValid
The allowance or reason is invalid.
ClaimDecisionReadCommitOwnership()
Claims exclusive completion ownership for protected units of work.
public DecisionReadCommitOwner ClaimDecisionReadCommitOwnership()
Returns
- DecisionReadCommitOwner
The opaque owner capability.
Exceptions
- ProtectedUnitOfWorkRequiresOwner
An owner has already claimed this unit.
Commit()
Commit the IUnitOfWork.
public Task Commit()
Returns
- Task
Awaitable task.
CommitAsOwner(DecisionReadCommitOwner)
Commits using the capability obtained by the transaction owner.
public Task CommitAsOwner(DecisionReadCommitOwner owner)
Parameters
ownerDecisionReadCommitOwnerThe claimed owner capability.
Returns
- Task
The commit task.
Exceptions
- ProtectedUnitOfWorkRequiresOwner
A different owner attempted to complete the unit.
Dispose()
public void Dispose()
Remarks
Disposal during an in-flight commit is a no-op; the commit completes the unit.
Exceptions
- ProtectedUnitOfWorkRequiresOwner
A claimed, open unit with enrolled decision reads must be completed by its owner.
EnforceReadProtection()
Begins invocation read protection before any event or read dependency is enrolled. Only the first caller receives the owning lifetime; subsequent leases cannot end enforcement.
public ReadProtectionFrame EnforceReadProtection()
Returns
- ReadProtectionFrame
The invocation frame, disposed by the owning command pipeline in a finally block.
Exceptions
- UnitOfWorkReadProtectionNotSupported
The implementation cannot enforce read protection.
- ReadProtectionMustBeginBeforeEnrollment
Events or dependencies have already been enrolled.
EnrolContributedRead(ContributedRead)
Atomically validates target, staged overlap and distinct contributions before enrolling a read.
public void EnrolContributedRead(ContributedRead contribution)
Parameters
contributionContributedReadThe stream or aggregate dependency.
Exceptions
- UnitOfWorkReadProtectionNotSupported
The implementation cannot enroll contributions.
- ContributedReadOriginNotValid
The contribution is not explicit or aggregate.
GetAppendConditions()
Gets the append conditions captured by the trusted commit.
public IReadOnlyList<AppendCondition> GetAppendConditions()
Returns
- IReadOnlyList<AppendCondition>
The immutable append-condition descriptions.
GetAppendErrors()
Get any errors that have occurred while attempting to commit in the IUnitOfWork.
public IEnumerable<AppendError> GetAppendErrors()
Returns
- IEnumerable<AppendError>
A collection of AppendError.
GetConcurrencyViolations()
Gets any concurrency violations thar occurred in the IUnitOfWork.
public IEnumerable<ConcurrencyViolation> GetConcurrencyViolations()
Returns
- IEnumerable<ConcurrencyViolation>
A collection of ConcurrencyViolation.
GetConstraintViolations()
Gets any constraint violations that occurred in the IUnitOfWork.
public IEnumerable<ConstraintViolation> GetConstraintViolations()
Returns
- IEnumerable<ConstraintViolation>
A collection of ConstraintViolation.
GetDecisionConflicts()
Gets the decision conflicts that refused the commit.
public IEnumerable<DecisionConflict> GetDecisionConflicts()
Returns
- IEnumerable<DecisionConflict>
Decision conflicts, if any, with the first conflicting event when the kernel reported it.
GetEvents()
Get the events that have occurred in the IUnitOfWork.
public IEnumerable<object> GetEvents()
Returns
- IEnumerable<object>
A collection of events.
OnCompleted(Action<IUnitOfWork>)
Set callback to be called when completed.
public void OnCompleted(Action<IUnitOfWork> callback)
Parameters
callbackAction<IUnitOfWork>The callback to call.
RefuseImmediateAppends()
Refuses immediate appends in this asynchronous flow without changing read admission. The first caller owns completion only if no completion owner or enforced read protection already exists. Otherwise the frame is refusal-only and completion stays with the existing owner. Later acquisitions cannot complete the unit or end refusal.
public ImmediateAppendRefusal RefuseImmediateAppends()
Returns
- ImmediateAppendRefusal
The refusal lifetime, or a borrowed frame for a nested acquisition. Commit through the existing owner when present.
Exceptions
- UnitOfWorkImmediateAppendRefusalNotSupported
The implementation cannot enforce append admission.
- ImmediateAppendRefusalRequiresOwner
Another unit owns the active refusal.
Rollback()
Rollback the IUnitOfWork.
public Task Rollback()
Returns
- Task
Awaitable task.
Exceptions
- ProtectedUnitOfWorkRequiresOwner
A claimed unit with enrolled decision reads must be rolled back by its owner.
- UnitOfWorkIsCompleting
A commit is in progress under the strict policy, or a claimed unit with enrolled decision reads is committing under the compatibility policy.
- UnitOfWorkIsAlreadyCommitted
The unit has already been committed.
- UnitOfWorkIsAlreadyRolledBack
The unit has already been rolled back.
RollbackAsOwner(DecisionReadCommitOwner)
Rolls back using the capability obtained by the transaction owner.
public Task RollbackAsOwner(DecisionReadCommitOwner owner)
Parameters
ownerDecisionReadCommitOwnerThe claimed owner capability.
Returns
- Task
The rollback task.
Exceptions
- ProtectedUnitOfWorkRequiresOwner
The capability does not match the claimed owner, or no owner has been claimed.
- UnitOfWorkIsCompleting
A commit is in progress, regardless of lifecycle policy.
- UnitOfWorkIsAlreadyCommitted
The unit has already been committed.
- UnitOfWorkIsAlreadyRolledBack
The unit has already been rolled back.
SuspendReadRegions()
Suspends the read regions this asynchronous flow inherited, without ending read protection.
public IDisposable SuspendReadRegions()
Returns
- IDisposable
The suspension, disposed by the host when the nested invocation ends.
Remarks
A read region flows with the asynchronous context, so a region opened by an outer invocation also covers a nested invocation it runs. A host that runs nested invocations under the same read protection suspends the inherited regions at the start of the nested one: reads are then refused as if no region were open, while regions opened inside the suspension apply as usual. Disposing the returned scope restores the inherited regions. Suspensions nest.
Exceptions
- UnitOfWorkReadProtectionNotSupported
The implementation cannot support read regions.
- ReadProtectionUnitMismatch
The unit does not own the active invocation.
TryGetLastCommittedEventSequenceNumber(out EventSequenceNumber?)
Try to get the EventSequenceNumber of the last committed event.
public bool TryGetLastCommittedEventSequenceNumber(out EventSequenceNumber? eventSequenceNumber)
Parameters
eventSequenceNumberEventSequenceNumberThe outputted EventSequenceNumber of the last committed event.
Returns
- bool
True if events were committed, false if not.
UseEffectReceipt(EffectKey, JsonNode?)
Enrolls one effect key in this unit's atomic commit. Re-enrolling the same key replaces its response until completion begins.
public void UseEffectReceipt(EffectKey key, JsonNode? response = null)
Parameters
keyEffectKeyThe occurrence effect key.
responseJsonNodeOptional plaintext JSON response without personal data.
Exceptions
- EffectReceiptsNotSupported
Atomic receipt support is absent or unknown.
- EffectReceiptResponseTooLarge
The response exceeds 64 KiB of UTF-8 JSON.
- UnitOfWorkEffectReceiptAlreadySet
Another key is already enrolled.