Skip to content

Explanation for when to handle domain events may be incorrect? #757

Open

Description

@roelofsmn

In the OrderingContext class there is the following method:

public async Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default)
  {
      // Dispatch Domain Events collection. 
      // Choices:
      // A) Right BEFORE committing data (EF SaveChanges) into the DB will make a single transaction including  
      // side effects from the domain event handlers which are using the same DbContext with "InstancePerLifetimeScope" or "scoped" lifetime
      // B) Right AFTER committing data (EF SaveChanges) into the DB will make multiple transactions. 
      // You will need to handle eventual consistency and compensatory actions in case of failures in any of the Handlers. 
      await _mediator.DispatchDomainEventsAsync(this);

      // After executing this line all the changes (from the Command Handler and Domain Event Handlers) 
      // performed through the DbContext will be committed
      _ = await base.SaveChangesAsync(cancellationToken);

      return true;
  }

I'm wondering if the explanation in the comments of this method is correct, given that the commands are handled through a PipelineBehavior TransactionBehavior, which has the following Handle method:

public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
    ...
    try
    {
        ...
        await strategy.ExecuteAsync(async () =>
        {
            Guid transactionId;

            await using var transaction = await _dbContext.BeginTransactionAsync();
            using (_logger.BeginScope(new List<KeyValuePair<string, object>> { new("TransactionContext", transaction.TransactionId) }))
            {
                ...
                response = await next();
                ...
                await _dbContext.CommitTransactionAsync(transaction);
                transactionId = transaction.TransactionId;
            }
            await _orderingIntegrationEventService.PublishEventsThroughEventBusAsync(transactionId);
        });
        return response;
    }
    catch (Exception ex)
    {
        ...
        throw;
    }
}

And, as explained in the EF Core docs, using the BeginTransactionAsync method makes that any subsequent call to SaveChangesAsync becomes part of the same transaction.

So, in this situation, it wouldn't matter whether await _mediator.DispatchDomainEventsAsync(this); was called before or after await base.SaveChangesAsync(cancellationToken);, right? Or what am I misunderstanding / missing?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions