Azure Function中ServiceBusMessage属性为空问题及重发需求求助
我已在业务层通过以下代码向Azure Service Bus订阅发送消息:
var sender = _serviceBusService.GetSender("event-send"); var message = new ServiceBusEvent() { SessionId = sessionId, CourseId = courseId, UserInfo = (BaseRequestUserInfo)userInfo, PlaybackId = playBackId, SsoProvider = userInfo?.SsoProvider, Type = MessageType.SessionEvent }; var body = JsonSerializer.Serialize(message); var sbMessage = new ServiceBusMessage(body); sbMessage.ApplicationProperties.Add("SsoProvider", userInfo.SsoProvider); sbMessage.ApplicationProperties.Add("Type", MessageType.SessionEvent.ToString()); await sender.SendMessageAsync(sbMessage);
同时创建了Azure Function处理该消息,在部分场景下需要根据Delivery Count设置消息的重新入队时间,但调试时发现ServiceBusMessage对象的所有属性均为空。请问该问题的原因是什么?如何解决?另外,Delivery Count是否存在于ApplicationProperties中,还是仅包含自定义属性?
我的Azure Function代码如下:
[FunctionName("VpSessionHandler")] public async Task Run([ServiceBusTrigger("event-send", "vp-session-event", Connection = "ServiceBusTopicConnectionString")] ServiceBusMessage mySbMsg, [ServiceBus("event-send", Microsoft.Azure.WebJobs.ServiceBus.ServiceBusEntityType.Topic, Connection = "ServiceBusTopicConnectionString")] ICollector<ServiceBusMessage> messageCollector) { try { var message = JsonSerializer.Deserialize<ServiceBusEvent>(mySbMsg.Body); var accessContext = _eventTrackerService.ChooseAccessTokenContext(message.SsoProvider); var accessToken = await accessContext.GetAccessTokenAsync(message.SsoProvider); var eventSender = _eventTrackerService.ChooseEventSessionSenderContext(message.SsoProvider); var sessionEventModel = new SessionEventModel() { PlaybackId = message.PlaybackId, UserInfo = message.UserInfo, AccessToken = accessToken, CourseId = message.CourseId, SessionId = message.SessionId, }; var rez = await eventSender.SendSessionEventApiAsync(sessionEventModel); if (!rez.IsSuccessStatusCode) { if (mySbMsg.ApplicationProperties.DeliveryCount > 1) { var delayTime = TimeSpan.FromSeconds(Math.Pow(2, mySbMsg.ApplicationProperties.DeliveryCount)); mySbMsg.ScheduledEnqueueTime = DateTime.UtcNow.Add(delayTime); messageCollector.Add(mySbMsg); } } } catch (Exception e) { Console.WriteLine(e); throw; } _logger.LogInformation($"C# ServiceBus topic trigger function processed message: {mySbMsg}"); }
补充说明:我曾尝试使用ServiceBusReceivedMessage作为参数,但需要用ServiceBusMessage来重新发送消息,而新建ServiceBusMessage会重置Delivery Count,不符合我的需求。
1. ServiceBusMessage属性为空的原因
Azure Functions的ServiceBus触发器中,ServiceBusMessage是发送专用的消息模型,框架不会自动将接收消息的系统属性(如Delivery Count、SessionId)映射到该类型,仅会填充消息体和自定义的ApplicationProperties。另外你代码中通过mySbMsg.ApplicationProperties.DeliveryCount访问投递次数是错误的——Delivery Count是系统属性,不属于自定义的ApplicationProperties集合,自然无法获取有效值。
2. 解决方法
要获取完整的消息元数据并实现符合需求的重新发送,按以下步骤操作:
步骤1:改用ServiceBusReceivedMessage作为触发器参数
ServiceBusReceivedMessage是接收消息的专用模型,会完整包含所有系统属性和自定义属性:
[FunctionName("VpSessionHandler")] public async Task Run([ServiceBusTrigger("event-send", "vp-session-event", Connection = "ServiceBusTopicConnectionString")] ServiceBusReceivedMessage receivedMsg, [ServiceBus("event-send", Microsoft.Azure.WebJobs.ServiceBus.ServiceBusEntityType.Topic, Connection = "ServiceBusTopicConnectionString")] ICollector<ServiceBusMessage> messageCollector)
步骤2:正确获取Delivery Count
直接通过receivedMsg.DeliveryCount访问当前投递次数:
if (!rez.IsSuccessStatusCode) { if (receivedMsg.DeliveryCount > 1) { var delayTime = TimeSpan.FromSeconds(Math.Pow(2, receivedMsg.DeliveryCount)); // 后续处理逻辑 } }
步骤3:基于接收消息创建可复用属性的发送消息
Delivery Count由Service Bus服务端维护,客户端无法手动设置,但可以通过复制原消息的核心属性,实现逻辑上的“重试递增”。重新发送的代码如下:
if (!rez.IsSuccessStatusCode) { if (receivedMsg.DeliveryCount > 1) { var delayTime = TimeSpan.FromSeconds(Math.Pow(2, receivedMsg.DeliveryCount)); // 创建新的发送消息,复制原消息的内容和属性 var sendMsg = new ServiceBusMessage(receivedMsg.Body) { SessionId = receivedMsg.SessionId, ScheduledEnqueueTime = DateTime.UtcNow.Add(delayTime) }; // 复制所有自定义ApplicationProperties foreach (var prop in receivedMsg.ApplicationProperties) { sendMsg.ApplicationProperties.Add(prop.Key, prop.Value); } messageCollector.Add(sendMsg); } }
注:重新发送的消息会被服务端视为新消息,Delivery Count从1开始,但原消息如果未被完成,后续投递时其自身的Delivery Count会自动递增。如果需要保留原消息的投递计数逻辑,可考虑使用DeferMessageAsync延迟原消息的投递,而非重新发送新消息。
3. Delivery Count的位置说明
- Delivery Count是Azure Service Bus的系统属性,由服务端维护,不属于自定义的
ApplicationProperties集合。 - 仅能通过
ServiceBusReceivedMessage.DeliveryCount属性访问该值。 - 客户端无法手动设置Delivery Count,服务端会自动维护每条消息的投递次数。
内容的提问来源于stack exchange,提问作者Ilya

