Issue: abp.io seems to create a two-phase commit distributed transaction when using distributed events
Abp.io latest source code sends messages (domainevents which should be called integrationevents in DDD I guess) when committing a transaction.
Thus, it can happen, that
- the EF transaction succeeds
- but the message bus is not reachable (for a longer time so that even using Polly does not help)

In that case, the events will never be sent!.
If I understand your code base correctly, you do send the distributed events within the EF Core transaction:
|
var result = await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken); |
|
|
|
await EntityChangeEventHelper.TriggerEventsAsync(changeReport); |
At least, you send it to the message bus and if that fails, the transaction is also not committed.
However, isn't that exactly what causes a two phase commit?
|
await TriggerEventsInternalAsync(changeReport); |
|
|
|
if (changeReport.IsEmpty() || UnitOfWorkManager.Current == null) |
|
{ |
|
return; |
|
} |
|
|
|
await UnitOfWorkManager.Current.SaveChangesAsync(); |
Shouldn't this be avoided?
Solution: The outbox pattern
The solution is using the outbox pattern:
Instead of directly sending the events to the event bus (e.g. RabbitMQ), they are
- serialized to the database (-> within the same transaction)
- later consumed by a polling consumer (polling consumer pattern)
Note: There is someone who wrote a 3 series blog article about this very problem and in part 3 he even developed a sample solution which is available on github: https://github.com/mizrael/DDD-School/
Please have a look!
(Here are part 1 and part 2 for reference)
Issue: abp.io seems to create a two-phase commit distributed transaction when using distributed events
Abp.io latest source code sends messages (domainevents which should be called integrationevents in DDD I guess) when committing a transaction.
Thus, it can happen, that
In that case, the events will never be sent!.
If I understand your code base correctly, you do send the distributed events within the EF Core transaction:
abp/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs
Lines 165 to 167 in 32402a9
At least, you send it to the message bus and if that fails, the transaction is also not committed.
However, isn't that exactly what causes a two phase commit?
abp/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Entities/Events/EntityChangeEventHelper.cs
Lines 48 to 55 in 6136fab
Shouldn't this be avoided?
Solution: The outbox pattern
The solution is using the outbox pattern:
Instead of directly sending the events to the event bus (e.g. RabbitMQ), they are
Note: There is someone who wrote a 3 series blog article about this very problem and in part 3 he even developed a sample solution which is available on github: https://github.com/mizrael/DDD-School/
Please have a look!
(Here are part 1 and part 2 for reference)