masstransit 依赖 rabbitmq 等消息代理,必须调用 startasync() 启动总线、正确配置 vhost 和权限,消费者需在启动前注册,消息类需保持一致,关闭 auto-ack 并配置重试与 dlq,saga 必须使用持久化仓储。

MassTransit 不是消息中间件,它必须依赖 RabbitMQ(或 Kafka、ASB)才能工作;跳过底层代理直接“用 MassTransit 实现队列”会卡在 BrokerUnreachableException 或静默丢消息。
BusControl 必须 StartAsync() 才能发消息
只注册服务、不启动总线,Publish() 和 Send() 会直接返回、不进队列、也不报错——这是最隐蔽的失败模式。
- .NET 6+ 中,确保
IBusControl被注册为AddHostedService,否则StartAsync()不会自动执行 - 控制台程序需显式调用:
await busControl.StartAsync(); - 发布消息前,建议加检查:
if (busControl.State == BusState.Started) { ... }
RabbitMQ 连接和 virtualHost 配置必须精确匹配
日志显示 “Connected to broker”,但队列为空、消费者不触发?大概率是 vhost 错了——比如连接字符串里写成 "myapp",而实际创建的是 "my-app",或漏掉 URL 编码(/ 要写成 %2F 当用查询参数时)。
- 本地开发推荐用 Docker 启动:
docker run -d -p 5672:5672 -p 15672:15672 rabbitmq:3-management - 配置中
cfg.Host("localhost", "/", h => { ... })的第二个参数是vhost,不是路径,不能省略 - 生产环境务必改掉默认账号
guest/guest,并给对应vhost授予configure、write、read权限
消费者必须在总线启动前注册,且类型定义要完全一致
如果在 StartAsync() 之后才调用 ConnectReceiveEndpoint(),或者用 new MyConsumer() 手动传入实例,消费者不会绑定到队列,消息堆积无响应。
- 所有
ReceiveEndpoint必须在AddMassTransit()的回调里声明,或在CreateUsingRabbitMq()的配置委托内完成 - 消费者注册必须用
cfg.Consumer<myconsumer>()</myconsumer>,由 DI 容器管理生命周期 - 消息类(如
public record OrderSubmitted)在发布端和消费端必须:命名空间相同、类名拼写一致、有 public set 或 init 属性、含无参构造函数(若用 System.Text.Json 反序列化)
ConfigureEndpoints 是自动建队列的关键,但不能替代手动 Ack 配置
ConfigureEndpoints(context) 会让 MassTransit 根据消费者类型名自动声明交换机、队列、绑定关系——但它默认开启自动确认(auto-ack),一旦消费者处理中途崩溃,消息就永久丢失。
- 真正在意可靠性,必须关闭 auto-ack:
cfg.UseMessageRetry(r => r.Interval(3, 1000))+cfg.UseScheduledRedelivery(...) - 显式控制预取数和手动确认:
cfg.PrefetchCount = 1;并在消费者Consume()方法里用context.ConsumeCompleted或抛异常触发重试 - 死信队列(DLQ)需在
ReceiveEndpoint中启用:cfg.DeadLetterExchange("dlx")
最容易被忽略的点是:Saga 状态机若没配持久化仓储(比如只用 InMemorySagaRepository),服务重启后所有进行中的事务状态全丢,补偿逻辑永远不会触发——这不是配置问题,是架构缺陷。










