What it is
MassTransit is a distributed application framework for .NET, abstracting over RabbitMQ, Azure Service Bus, Amazon SQS and Kafka with sagas and routing built in.
Define message contracts as records and consumers as classes. MassTransit handles serialisation, topology, retries and dead-lettering.
Installation
dotnet add package MassTransitGetting started
The smallest useful thing you can do with it, and what each part means.
csharp
public record OrderSubmitted(Guid OrderId, decimal Total);
public class OrderSubmittedConsumer : IConsumer<OrderSubmitted>
{
public async Task Consume(ConsumeContext<OrderSubmitted> context)
{
await _inventory.ReserveAsync(context.Message.OrderId);
// Publishing from the consumer participates in the same transaction
// when the outbox is enabled.
await context.Publish(new InventoryReserved(context.Message.OrderId));
}
}
services.AddMassTransit(x =>
{
x.AddConsumer<OrderSubmittedConsumer>();
x.UsingRabbitMq((ctx, cfg) =>
{
cfg.Host("localhost", "/", h => { h.Username("guest"); h.Password("guest"); });
cfg.ConfigureEndpoints(ctx); // convention-based queue naming
});
});Advanced usage
Where the library earns its place over a simpler alternative.
csharp
public class OrderState : SagaStateMachineInstance
{
public Guid CorrelationId { get; set; }
public string CurrentState { get; set; } = default!;
}
public class OrderStateMachine : MassTransitStateMachine<OrderState>
{
public OrderStateMachine()
{
Initially(When(Submitted)
.TransitionTo(AwaitingPayment));
During(AwaitingPayment,
When(PaymentReceived).TransitionTo(Paid).Publish(ctx => new OrderPaid(ctx.Saga.CorrelationId)),
When(PaymentFailed).TransitionTo(Cancelled));
}
}
// Outbox: publish only if the database transaction commits.
x.AddEntityFrameworkOutbox<AppDb>(o => { o.UsePostgres(); o.UseBusOutbox(); });Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- Messages land in the _error queue
- The consumer threw after exhausting retries. Inspect the fault headers, fix the cause, and requeue from the error queue.
- Messages are published but never consumed
- A topology mismatch — usually the consumer was not registered before ConfigureEndpoints, so no queue was bound.
Best practices
- Enable the transactional outbox whenever a consumer both writes to a database and publishes.
- Make consumers idempotent; at-least-once delivery means redelivery will happen.
- Define messages as records in a shared contracts assembly.
- Check licensing before upgrading — v9 is commercial, v8 is open source.
Background
Why it exists, and what it was reacting to.
MassTransit lets you write message consumers once and switch transports by configuration, and adds the patterns — sagas, outbox, retries — that raw broker clients leave to you.
