public async Task <IAggregateUpdateResult <TExecutionResult> > UpdateAsync <TAggregate, TIdentity, TExecutionResult>(TIdentity id, ISourceId sourceId, Func <TAggregate, CancellationToken, Task <TExecutionResult> > updateAggregate, CancellationToken cancellationToken) where TAggregate : class, IAggregateRoot <TIdentity> where TIdentity : IIdentity where TExecutionResult : IExecutionResult { var aggregateUpdateResult = await _transientFaultHandler.TryAsync( async c => { var aggregate = await LoadAsync <TAggregate, TIdentity>(id, c).ConfigureAwait(false); if (aggregate.HasSourceId(sourceId)) { throw new DuplicateOperationException( sourceId, id, $"Aggregate '{typeof(TAggregate).PrettyPrint()}' has already had operation '{sourceId}' performed"); } cancellationToken = _cancellationConfiguration.Limit(cancellationToken, CancellationBoundary.BeforeUpdatingAggregate); var result = await updateAggregate(aggregate, c).ConfigureAwait(false); if (!result.IsSuccess) { _logger.LogDebug( "Execution failed on aggregate {AggregateType}, disregarding any events emitted", typeof(TAggregate).PrettyPrint()); return(new AggregateUpdateResult <TExecutionResult>(result, null)); } cancellationToken = _cancellationConfiguration.Limit(cancellationToken, CancellationBoundary.BeforeCommittingEvents); var domainEvents = await aggregate.CommitAsync( _eventJsonSerializer, sourceId, cancellationToken) .ConfigureAwait(false); return(new AggregateUpdateResult <TExecutionResult>(result, domainEvents)); }, Label.Named("aggregate-update"), cancellationToken) .ConfigureAwait(false); if (aggregateUpdateResult.Result.IsSuccess && aggregateUpdateResult.DomainEvents.Any()) { var domainEventPublisher = _serviceProvider.GetRequiredService <IDomainEventPublisher>(); await domainEventPublisher.PublishAsync( aggregateUpdateResult.DomainEvents, cancellationToken) .ConfigureAwait(false); } return(aggregateUpdateResult); }
public async Task PublishAsync( IReadOnlyCollection <IDomainEvent> domainEvents, CancellationToken cancellationToken) { cancellationToken = _cancellationConfiguration.Limit(cancellationToken, CancellationBoundary.BeforeUpdatingReadStores); await PublishToReadStoresAsync(domainEvents, cancellationToken).ConfigureAwait(false); cancellationToken = _cancellationConfiguration.Limit(cancellationToken, CancellationBoundary.BeforeNotifyingSubscribers); await PublishToSubscribersOfAllEventsAsync(domainEvents, cancellationToken).ConfigureAwait(false); // Update subscriptions AFTER read stores have been updated await PublishToSynchronousSubscribersAsync(domainEvents, cancellationToken).ConfigureAwait(false); await PublishToAsynchronousSubscribersAsync(domainEvents, cancellationToken).ConfigureAwait(false); await PublishToSagasAsync(domainEvents, cancellationToken).ConfigureAwait(false); }