public async Task PublishAsync <TAggregate, TIdentity>( TIdentity id, IReadOnlyCollection <IDomainEvent> domainEvents, CancellationToken cancellationToken) where TAggregate : IAggregateRoot <TIdentity> where TIdentity : IIdentity { // ARGH, dilemma, should we pass the cancellation token to read model update or not? var updateReadStoresTasks = _readStoreManagers .Select(rsm => rsm.UpdateReadStoresAsync(domainEvents, CancellationToken.None)); await Task.WhenAll(updateReadStoresTasks).ConfigureAwait(false); // Update subscriptions AFTER read stores have been updated await _dispatchToEventSubscribers.DispatchAsync(domainEvents, cancellationToken).ConfigureAwait(false); }
public async Task PublishAsync <TAggregate>( ICommand <TAggregate> command, CancellationToken cancellationToken) where TAggregate : IAggregateRoot { if (command == null) { throw new ArgumentNullException("command"); } var commandType = command.GetType().Name; var aggregateType = typeof(TAggregate); _log.Verbose( "Executing command '{0}' on aggregate '{1}' with ID '{2}'", commandType, aggregateType.Name, command.Id); var domainEvents = await Retry.ThisAsync( async() => { var aggregate = await _eventStore.LoadAggregateAsync <TAggregate>(command.Id, cancellationToken).ConfigureAwait(false); await command.ExecuteAsync(aggregate, cancellationToken).ConfigureAwait(false); return(await aggregate.CommitAsync(_eventStore, cancellationToken).ConfigureAwait(false)); }, _configuration.NumberOfRetriesOnOptimisticConcurrencyExceptions, new [] { typeof(OptimisticConcurrencyException) }, _configuration.DelayBeforeRetryOnOptimisticConcurrencyExceptions) .ConfigureAwait(false); if (!domainEvents.Any()) { _log.Verbose( "Execution command '{0}' on aggregate '{1}' with ID '{2}' did NOT result in any domain events", commandType, aggregateType.Name, command.Id); return; } // TODO: Determine if we can use cancellation token after there, this should be the "point of no return" await _readStoreManager.UpdateReadStoresAsync <TAggregate>(command.Id, domainEvents, CancellationToken.None).ConfigureAwait(false); await _dispatchToEventSubscribers.DispatchAsync(domainEvents).ConfigureAwait(false); }