Example #1
0
        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);
        }
Example #2
0
        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);
        }