Azure服务总线队列消费者序列号与生产者及门户返回值不一致问题
问题原因
该现象是Azure Service Bus的固有设计,并非代码逻辑错误:
调用ScheduleMessageAsync()返回的序列号是定时调度任务专属序列号,仅用于标识待触发的定时调度任务,此时消息尚未正式写入队列存储。当到达你设置的入队时间时,Service Bus会将消息正式写入队列,此时会给消息重新分配一个全局唯一的队列消息序列号,也就是消费者侧通过args.Message.SequenceNumber拿到的值,二者天然不相等。
解决方案
方案1:使用自定义属性关联(推荐)
在生产者发送消息时,主动添加全局唯一的自定义属性作为关联标识,存入数据库的同时写入消息属性,消费者侧读取该属性匹配数据库记录即可。
修改后的生产者代码:
public async Task<Guid> SendMessage(string messageBody, DateTimeOffset scheduledEnqueueTimeUtc) { await using (ServiceBusClient client = new ServiceBusClient(_config["ServiceBus:Connection"])) { ServiceBusSender sender = client.CreateSender(_config["ServiceBus:Queue"]); ServiceBusMessage message = new ServiceBusMessage(messageBody); // 生成自定义唯一标识 var customMsgId = Guid.NewGuid(); // 写入消息自定义属性 message.ApplicationProperties["CustomMessageId"] = customMsgId.ToString(); // 调度消息 await sender.ScheduleMessageAsync(message, scheduledEnqueueTimeUtc); // 返回自定义标识存入数据库 return customMsgId; } }
消费者侧读取属性匹配:
private async Task MessageHandler(ProcessMessageEventArgs args) { string body = args.Message.Body.ToString(); JObject jsonObject = JObject.Parse(body); var eventStatus = (string)jsonObject["EventStatus"]; // 读取自定义标识查询数据库 var customMsgId = args.Message.ApplicationProperties["CustomMessageId"].ToString(); // 后续逻辑用customMsgId匹配数据库记录即可 await args.CompleteMessageAsync(args.Message); int result = await dbContext.SaveChangesAsync(); }
方案2:使用调度序列号匹配
如果不想新增自定义属性,可以直接在消费者侧读取ScheduledEnqueueSequenceNumber属性,该值和生产者调用ScheduleMessageAsync()返回的序列号完全一致:
private async Task MessageHandler(ProcessMessageEventArgs args) { string body = args.Message.Body.ToString(); JObject jsonObject = JObject.Parse(body); var eventStatus = (string)jsonObject["EventStatus"]; // 读取调度序列号,和你之前存入数据库的序列号匹配 long scheduledSequenceNumber = args.Message.ScheduledEnqueueSequenceNumber; await args.CompleteMessageAsync(args.Message); int result = await dbContext.SaveChangesAsync(); }
内容的提问来源于stack exchange,提问作者chuckd
相关产品推荐
相关产品推荐

