Masstransit框架中实现消息的动态监听
在使用消息队列中,会有这么一个场景:要求发送的queue是按照元数据配置自动生成,监听队列的逻辑也要对应的自动生成。这种
动态监听队列的场景可以使用Masstransit框架解决。
1.Producer
消息的生成者搭建一个webapi项目,指定virtual host,可以自动配置queue的名称
public void ConfigureServices(IServiceCollection services) { services.AddMassTransit(x => { x.UsingRabbitMq((context, config) => { config.Host("rabbitmq://localhost:5672", host => { host.Username("root"); host.Password("root"); }); }); }); services.AddControllers(); }
然后写一个api程序
[ApiController] [Route("[controller]")] public class PublishController : ControllerBase { private readonly IPublishEndpoint _publishEndpoint; public PublishController(IPublishEndpoint publishEndpoint) { _publishEndpoint = publishEndpoint; } [HttpGet] public async Task<string> Get(string name) { await _publishEndpoint.Publish(new OrderEto { Id = Guid.NewGuid(), Name = name, CreationTime = DateTime.Now }); return "success"; } }
注意:OrderEto这个实体是共享同一个命名空间与名称的类
2.Consumer
消费者则使用通用主机项目
public static async Task Main(string[] args) { await Host.CreateDefaultBuilder(args) .ConfigureServices(services => { services.AddMassTransit(x => { x.AddConsumer<OrderEtoConsumer>(typeof(OrderEtoConsumerDefinition)); x.UsingRabbitMq((context, config) => { config.Host("rabbitmq://localhost:5672", hostconfig => { hostconfig.Username("root"); hostconfig.Password("root"); }); config.ConfigureEndpoints(context); }); }); }) .Build() .RunAsync(); }
然后写一个consumer的类,这个类就是去消费的具体逻辑
public class OrderEtoConsumer : IConsumer<OrderEto> { public Task Consume(ConsumeContext<OrderEto> context) { Console.WriteLine($"MassTransit.Consumer.One 收到消息:{JsonSerializer.Serialize(context.Message)}"); return Task.CompletedTask; } } public class OrderEtoConsumerDefinition : ConsumerDefinition<OrderEtoConsumer> { protected override void ConfigureConsumer(IReceiveEndpointConfigurator endpointConfigurator, IConsumerConfigurator<OrderEtoConsumer> consumerConfigurator) { endpointConfigurator.UseMessageRetry(r => r.Intervals(500, 1000)); } }
将两个站点同时启动,进行测试:
所以结论:
消费者的Model确定后,就相当于某类消息固定了,在不特指queue的情况下,可以监听所有queue的信息,如果在代码指定了具体的queue的名称则实现不了。
因为此时需要定义消息体跟consumer处理类。