Migrate Mocha from 16.6 to 16.7
Update every Mocha.* package in the application to version 16.7 before applying these changes.
Behavioral breaking changes#
The Postgres outbox requires a transaction#
PublishAsync and SendAsync through the outbox registered with UsePostgresOutbox() now require an open database transaction on the DbContext or an ambient TransactionScope. Without one, they throw an InvalidOperationException and no message is written. In 16.6, such a message was inserted into the outbox table immediately, outside any later SaveChangesAsync, so it was dispatched even when the entity changes were never saved.
Replies, faults, requests, and scheduled messages are not affected.
The code paths that typically published without a transaction in 16.6 need one of these changes:
-
Consumers get a transaction from
UseTransaction():Diff builder.Services .AddMessageBus() .AddEntityFramework<AppDbContext>(p => { p.UsePostgresOutbox(); + p.UseTransaction(); }) .AddRabbitMQ(); -
Mediator handlers get a transaction from
UseEntityFrameworkTransactions<TContext>():Diff builder.Services .AddMediator() + .UseEntityFrameworkTransactions<AppDbContext>(); -
Other code, such as API endpoints and background services, opens a transaction on the DbContext:
Diff +await using var transaction = await db.Database.BeginTransactionAsync(cancellationToken); + db.Orders.Add(order); await bus.PublishAsync(new OrderPlaced(order.Id), cancellationToken); await db.SaveChangesAsync(cancellationToken); + +await transaction.CommitAsync(cancellationToken);
Direct bus publishes use the first DbContext registered with UsePostgresOutbox(). A transaction on a different DbContext does not satisfy the requirement.
To keep the 16.6 behavior, set RequireTransaction to false:
builder.Services
.AddMessageBus()
.AddEntityFramework<AppDbContext>(p =>
{
- p.UsePostgresOutbox();
+ p.UsePostgresOutbox(o => o.RequireTransaction = false);
})
.AddRabbitMQ();With RequireTransaction set to false, a message published outside a transaction is written to the outbox table immediately. Inside a transaction, it is written as part of that transaction.
See Reliability for details.
Edit this page on GitHub