Azure Service Bus发送消息偶发异常:已释放对象/连接关闭无法创建会话
解决Azure Service Bus消息发送偶发失败的问题
你的偶发报错核心是静态QueueClient的不当复用+频繁创建销毁连接导致的并发冲突,结合代码细节我来拆解问题并给出修复方案:
问题根源分析
静态
QueueClient的并发冲突
你的queueClient是静态变量,但每次调用SendQueueMessage都会重新实例化它,还在方法末尾执行CloseAsync()。当数千个异步任务同时跑时,多个线程会同时修改这个静态变量:- 线程A刚创建
queueClient开始发消息,线程B就把queueClient重新赋值成新实例 - 线程A执行
CloseAsync()时,关闭的可能已经是线程B刚创建的实例,反过来线程B的发送操作就会访问一个已被关闭/释放的对象,触发Cannot access a disposed object或连接关闭相关错误
- 线程A刚创建
QueueClient生命周期误用
Azure Service Bus的QueueClient是设计为可复用的长连接对象,频繁创建销毁会导致连接池不稳定,既浪费资源又增加连接类错误的概率。
修复方案
1. 改为单例模式复用QueueClient
把QueueClient改成全局单例,仅在应用启动时初始化一次,应用关闭时再统一关闭,避免每次发送都创建/销毁连接。
2. 修复后的代码示例
public class ServiceBusService { // 用懒加载实现线程安全的单例初始化 private static readonly Lazy<IQueueClient> _lazyQueueClient = new Lazy<IQueueClient>(() => new QueueClient(AzureUtils.SERVICE_BUS_CONNECTIONSTRING, "eventqueue")); private static IQueueClient QueueClient => _lazyQueueClient.Value; public async Task SendQueueMessage(JObject jObject, DateTime? scheduledEnqueueTimeUtc = null) { string scheduledTime = scheduledEnqueueTimeUtc?.ToLongTimeString() ?? ""; try { var message = new Message(Encoding.UTF8.GetBytes(jObject.ToString())); if (scheduledEnqueueTimeUtc.HasValue) { message.ScheduledEnqueueTimeUtc = scheduledEnqueueTimeUtc.Value; } // 直接复用单例QueueClient,无需每次创建和关闭 await QueueClient.SendAsync(message); } catch (Exception e) { Trace.TraceError($"{Tag()} {e.InnerException?.Message ?? ""} {e.Message}"); } } // 新增:在应用关闭时调用此方法统一关闭QueueClient public static async Task CloseQueueClientAsync() { if (_lazyQueueClient.IsValueCreated) { await QueueClient.CloseAsync(); } } private string Tag() => "[ServiceBusService]"; }
3. 优化异步任务调用
原来的Task.Run(() => new ServiceBusService().SendQueueMessage(busMessageObject))可以简化为直接调用异步方法(上下文允许的话),或者正确处理后台任务的异常:
// 若在异步上下文,直接await调用 await new ServiceBusService().SendQueueMessage(busMessageObject); // 若需后台执行,建议捕获异常避免静默失败 _ = Task.Run(async () => { try { await new ServiceBusService().SendQueueMessage(busMessageObject); } catch (Exception ex) { Trace.TraceError($"后台发送消息失败: {ex.Message}"); } });
额外建议
- 用批量发送:如果要发数千条消息,用
SendBatchAsync批量发送能大幅提升性能,减少连接开销 - 配置重试策略:Service Bus SDK内置重试机制,可配置重试策略处理临时连接错误,提升可靠性
内容的提问来源于stack exchange,提问作者EK_AllDay
相关产品推荐
相关产品推荐

