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

.NET 8升级后Service Bus消息复制异常及重试失效问题求助

.NET 8升级后Service Bus消息重发丢失自定义属性及重试计数器失效的解决方案

问题分析

升级到.NET 8后,原有的Service Bus消息重发逻辑出现两个问题:

  • 使用new ServiceBusMessage(message)复制消息时,自定义属性未被完整复制,导致后续重试时交易编号丢失
  • 手动发送新消息的方式无法延续原消息的DeliveryCount,重试计数器自动递增失效

原因

Azure.Messaging.ServiceBus在适配.NET 8的版本中,ServiceBusMessage的复制构造函数行为发生了变更,不再默认复制所有自定义属性;同时,重新发送的新消息属于全新投递,自然不会继承原消息的投递计数。

解决方案

1. 手动完整复制自定义属性

放弃依赖复制构造函数,手动复制原消息的所有自定义属性和必要系统属性到新消息中:

// 基于原消息体创建新消息
var newMessage = new ServiceBusMessage(message.Body)
{
    ScheduledEnqueueTime = DateTime.UtcNow.AddMinutes(_config.HoldServiceBusMsgMinutes),
    // 按需复制系统属性,比如消息ID、关联ID
    MessageId = message.MessageId,
    CorrelationId = message.CorrelationId
};

// 遍历复制所有自定义属性
foreach (var prop in message.ApplicationProperties)
{
    newMessage.ApplicationProperties[prop.Key] = prop.Value;
}

2. 维护自定义重试计数器

由于新消息无法继承原DeliveryCount,需要在自定义属性中维护专属的重试计数:

// 读取当前重试计数:首次重试用原消息DeliveryCount,后续从自定义属性读取
int currentRetryCount;
if (message.ApplicationProperties.TryGetValue("RetryCount", out var retryVal) && int.TryParse(retryVal.ToString(), out currentRetryCount))
{
    currentRetryCount++;
}
else
{
    currentRetryCount = message.DeliveryCount;
}

// 将更新后的计数存入新消息的自定义属性
newMessage.ApplicationProperties["RetryCount"] = currentRetryCount;

优化后的完整代码

catch (Exception ex) when (ex.Message.Contains("Not Found"))
{
    var parsedMessage = _messageReceiver.ParseServiceBusMessage(message);

    // 获取当前重试计数
    int currentRetryCount;
    if (message.ApplicationProperties.TryGetValue("RetryCount", out var retryVal) && int.TryParse(retryVal.ToString(), out currentRetryCount))
    {
        currentRetryCount++;
    }
    else
    {
        currentRetryCount = message.DeliveryCount;
    }

    if (currentRetryCount <= _config.MaxRetryCount)
    {
        using (var ts = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
        {
            await _messageReceiver.CompleteMessageAsync(message, messageReceiver);

            // 手动构建新消息并复制所有必要属性
            var newMessage = new ServiceBusMessage(message.Body)
            {
                ScheduledEnqueueTime = DateTime.UtcNow.AddMinutes(_config.HoldServiceBusMsgMinutes),
                MessageId = message.MessageId,
                CorrelationId = message.CorrelationId
            };

            // 复制原消息自定义属性
            foreach (var prop in message.ApplicationProperties)
            {
                newMessage.ApplicationProperties[prop.Key] = prop.Value;
            }
            // 更新自定义重试计数
            newMessage.ApplicationProperties["RetryCount"] = currentRetryCount;

            await _serviceBusClient.SendAsync(newMessage);

            _logger.LogInformation("Retry counter: {retryCount}  Processing order number {transactionNumber} resulted in not found condition. Resubmitted to service bus", currentRetryCount, parsedMessage.Transaction);
            ts.Complete();
        }
    }
    else
    {
        _logger.LogError("Max retry count reached for transaction number {transactionNumber}", parsedMessage.Transaction);
        await _messageReceiver.DeadletterMessageAsync(message, messageReceiver, ex);
    }
}

额外提示

  • 如果不需要高度自定义的重试逻辑,可以考虑使用Service Bus内置的重试策略,结合消息的ScheduledEnqueueTime配置延迟,减少手动维护成本
  • 确保Azure.Messaging.ServiceBus NuGet包更新到适配.NET 8的最新稳定版本,避免版本兼容问题

内容的提问来源于stack exchange,提问作者Chris

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 03:55:55