如何配置MassTransit确保消费者仅响应指定消息类型?
问题描述
我们希望在不同的Azure Web Apps中结合Azure Service Bus使用MassTransit。为遵循现有模式,我们按消息类型定义消费者及其对应的消息,但发现当两个消息类型的成员完全相同时,所有注册了成员相同类型的消费者都会被触发。
例如,我们有两个消费者方法:Consume(ConsumeContext<OrderCancelled> context) 和 Consume(ConsumeContext<OrderCreated> context),对应的消息类分别是:
public record OrderCancelled(int OrderId, DateTime Date)
和
public record OrderCreated(int OrderId, DateTime Date)
测试发现,当其中一个消息发布到消费者订阅的Azure Service Bus主题时,两个消费者都会被调用。我们注意到MassTransit会为消息添加自定义头字段:
MT-MessageType: urn:message:Business.Messages.Events:OrderCancelled
显然,即使context.Message是反序列化的JSON,MassTransit也能识别发送消息的类型(该MT-MessageType可在context.ReceiveContext.TransportHeaders中获取)。请问是否存在配置项可以确保仅目标消费者响应指定类型的消息?
谢谢,Paul
这个问题的核心是Azure Service Bus默认的订阅过滤逻辑——当消息结构完全一致时,基于消息体的规则会匹配到多个消费者。要解决这个问题,你需要配置基于MT-MessageType头的订阅过滤规则,让Service Bus在路由阶段就只把消息发送给匹配的订阅。
1. 为消费者订阅添加消息类型SQL过滤
在注册消费者到MassTransit时,手动为每个消费者的订阅添加基于MT-MessageType的SQL过滤规则:
services.AddMassTransit(x => { x.AddConsumer<OrderCancelledConsumer>(); x.AddConsumer<OrderCreatedConsumer>(); x.UsingAzureServiceBus((context, cfg) => { cfg.Host("your-azure-service-bus-connection-string"); // 为OrderCancelledConsumer配置带过滤的订阅 cfg.Subscribe("your-topic-name", s => { s.Consumer<OrderCancelledConsumer>(context); s.SqlFilter($"MT-MessageType = 'urn:message:Business.Messages.Events:OrderCancelled'"); }); // 为OrderCreatedConsumer配置带过滤的订阅 cfg.Subscribe("your-topic-name", s => { s.Consumer<OrderCreatedConsumer>(context); s.SqlFilter($"MT-MessageType = 'urn:message:Business.Messages.Events:OrderCreated'"); }); cfg.ConfigureEndpoints(context); }); });
2. 禁用默认自动拓扑配置(可选)
如果你的消费者是通过AddConsumer自动绑定主题的,建议禁用默认的拓扑自动配置,避免MassTransit生成的默认规则干扰自定义过滤:
x.UsingAzureServiceBus((context, cfg) => { // 关闭默认消费拓扑自动配置,手动控制订阅规则 cfg.ConfigureConsumeTopology = false; // 后续添加手动订阅和过滤规则,如步骤1所示 });
3. 验证过滤规则
配置完成后,可登录Azure门户进入对应的Service Bus主题,查看每个订阅的过滤规则,确认MT-MessageType的SQL过滤已正确添加。此时发布OrderCancelled消息时,只有匹配该类型过滤规则的消费者会收到消息,OrderCreated消费者不会被触发。
原理说明
MassTransit本身通过MT-MessageType头识别消息类型,但Azure Service Bus默认的订阅逻辑是基于消息体结构匹配。通过手动添加基于MT-MessageType的SQL过滤,我们让Service Bus在路由阶段就完成消息筛选,从根源上避免无关消费者被触发。
内容的提问来源于stack exchange,提问作者Paul Cuttler

