You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 19:27:04