masstransit消息失败主因是总线未启动、vhost配置错误或消费者注册时机不当:buscontrol需startasync()后才能发消息;vhost须严格匹配且url编码;receiveendpoint必须在启动前注册;消费者需addconsumer()注册;重试策略须在receiveendpoint内配置。

MassTransit 消息发不出去、消费者不触发、连接看似成功却收不到消息——90% 的问题不是框架 bug,而是总线没启动、vhost 配置错、或消费者注册时机不对。
BusControl 必须 StartAsync() 后才能发布消息
只调用 Bus.Factory.CreateUsingRabbitMq() 或在 AddMassTransit() 里配了 RabbitMQ,但没真正启动总线,Publish() 就会静默丢弃,不报错、不进队列、日志也几乎没提示。
-
BusControl是个状态机,未StartAsync()前处于Created状态,所有发送操作被直接忽略 - .NET 6+ Host 模型中,必须把
IBusControl注册为AddHostedService,否则不会自动调用StartAsync() - 控制台程序要显式 await:
await busControl.StartAsync();—— 缺这行,消息就发不出去
RabbitMQ vhost 和连接字符串必须严格匹配且 URL 编码
日志显示 “Connected to broker”,但 GetQueues() 查不到消费者队列,或者发消息后队列始终为空,大概率是 vhost 不一致。
- RabbitMQ 默认 vhost 是
/,但云厂商(如腾讯云、阿里云)实例常默认用/default或自定义路径(如/myapp) - 连接字符串里的 vhost 必须 URL 编码:比如
/my/space要写成/my%2Fspace,否则连接会被拒绝或路由失败 - 用
curl -u user:pass http://localhost:15672/api/vhosts查实际存在的 vhost 列表,别凭印象写 - 配置时必须显式指定:
cfg.Host("localhost", 5672, h => { h.VirtualHost("/"); ... })
ReceiveEndpoint 必须在总线启动前注册
如果先 StartAsync(),再调用 bus.ConnectReceiveEndpoint() 或在总线启动后动态注册 ReceiveEndpoint,消费者根本不会监听队列,消息进来就堆积或按策略丢弃。
- 正确写法:所有
ReceiveEndpoint必须在CreateUsingRabbitMq()的配置委托内声明,或在AddMassTransit()回调中通过ConfigureEndpoints(context)自动发现 - 错误写法示例:
var bus = Bus.Factory.CreateUsingRabbitMq(); await bus.StartAsync(); bus.ConnectReceiveEndpoint("my-queue", cfg => { ... });—— 此时已失效 - 消费者类必须用
AddConsumer<t>()</t>注册,且类型需与消息契约完全一致(命名空间、程序集、版本都要对)
重试和超时策略必须在 ReceiveEndpoint 级别配置
全局 UseMessageRetry() 不生效,必须在每个 ReceiveEndpoint 内部配置,否则异常消息不会重试,直接进 error 队列或丢弃。
- 重试策略不能只写在消费者类里,必须在 endpoint 配置中嵌套:
e.UseMessageRetry(r => r.Intervals(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10))) - 超时控制靠
e.PrefetchCount = 1+e.TimeToLive = TimeSpan.FromMinutes(5),前者防消息堆积阻塞,后者防死信积压 - 注意
TimeToLive是消息级 TTL,而AutoDelete是队列级行为,两者作用对象不同,别混用
最容易被忽略的是:vhost 的 URL 编码和 StartAsync() 的执行时机。这两个点不卡准,整个消息流就断在第一环,后续所有逻辑都白搭。










