Service Bus定期续锁仍丢锁:长任务超20分钟消息过期排查
问题
我正在排查Azure Service Bus消息过期的问题:当任务时长超过约20分钟时,即便定期续锁,消息仍会触发MessageLockLost错误。当前配置是用接收器处理长任务,启动子线程每隔约4分钟续锁(锁时长设为5分钟),17分钟以内的任务正常,20分钟及以上就失败。
现有代码配置
接收器初始化
var options = new ServiceBusReceiverOptions { ReceiveMode = ServiceBusReceiveMode.PeekLock }; _receiver = _serviceBusClient.CreateReceiver( messageSource.EntityName, messageSource.SubscriptionName, options);
获取消息
var message = await _receiver.ReceiveMessageAsync(TimeSpan.FromMinutes(2), cancellationToken: cancellationToken);
消息续锁逻辑
int interval = Convert.ToInt32((message.LockedUntil - DateTimeOffset.UtcNow).TotalMilliseconds * 3 / 4); if (interval < 1) interval = 1; var timercallBack = new TimerCallback(async obj => await RenewAsync((ServiceBusReceivedMessage)obj, cancellationToken)); var timer = new Timer(timercallBack, message, interval, interval);
续锁函数
private async Task RenewAsync(ServiceBusReceivedMessage msg, CancellationToken cancellationToken) { await _receiver.RenewMessageLockAsync(msg, cancellationToken); _logger.Debug($"Message {msg.MessageId}: Message processing time: {DateTime.UtcNow - msg.EnqueuedTime}. {nameof(msg.LockedUntil)}: {msg.LockedUntil}. Delivery count: {msg.DeliveryCount}."); }
消息完成逻辑
_logger.Debug($"Completing message {msg.Msg.MessageId}..."); await _receiver.CompleteMessageAsync(msg, cancellationToken);
错误日志
25 Nov 2023 17:23:16.716: New message received.. 25 Nov 2023 17:27:01.935: Message 5c79f94f483c4aa58404b5a2ce8e0f3c: Message processing time: 08:22:13.3302606. LockedUntil: 11/25/2023 2:32:02 PM +00:00. Delivery count: 10. 25 Nov 2023 17:30:47.157: Message 5c79f94f483c4aa58404b5a2ce8e0f3c: Message processing time: 08:25:58.5522655. LockedUntil: 11/25/2023 2:35:47 PM +00:00. Delivery count: 10. 25 Nov 2023 17:34:32.384: Message 5c79f94f483c4aa58404b5a2ce8e0f3c: Message processing time: 08:29:43.7797238. LockedUntil: 11/25/2023 2:39:32 PM +00:00. Delivery count: 10. 25 Nov 2023 17:38:17.554: Message 5c79f94f483c4aa58404b5a2ce8e0f3c: Message processing time: 08:33:28.9497474. LockedUntil: 11/25/2023 2:43:17 PM +00:00. Delivery count: 10. 25 Nov 2023 17:42:02.758: Message 5c79f94f483c4aa58404b5a2ce8e0f3c: Message processing time: 08:37:14.1531070. LockedUntil: 11/25/2023 2:47:03 PM +00:00. Delivery count: 10. 25 Nov 2023 17:45:47.965: Message 5c79f94f483c4aa58404b5a2ce8e0f3c: Message processing time: 08:40:59.3606038. LockedUntil: 11/25/2023 2:50:48 PM +00:00. Delivery count: 10. 25 Nov 2023 17:49:33.174: Message 5c79f94f483c4aa58404b5a2ce8e0f3c: Message processing time: 08:44:44.5690526. LockedUntil: 11/25/2023 2:54:33 PM +00:00. Delivery count: 10. 25 Nov 2023 17:50:16.727: Completing message 5c79f94f483c4aa58404b5a2ce8e0f3c... 25 Nov 2023 17:50:16.779: The lock supplied is invalid. Either the lock expired, or the message has already been removed from the queue, or was received by a different receiver instance. (MessageLockLost).
所有续锁操作日志显示成功,但完成消息时触发锁失效错误。已尝试切换到ServiceBusProcessor,问题依旧。
修复提示
- 更新消息实例的锁信息:
RenewMessageLockAsync会返回更新后的ServiceBusReceivedMessage,但当前代码未用返回值替换原实例,导致后续操作使用旧锁令牌(续期后旧令牌失效)。修改续锁函数:
private async Task RenewAsync(ref ServiceBusReceivedMessage msg, CancellationToken cancellationToken) { msg = await _receiver.RenewMessageLockAsync(msg, cancellationToken); _logger.Debug($"Message {msg.MessageId}: Message processing time: {DateTime.UtcNow - msg.EnqueuedTime}. {nameof(msg.LockedUntil)}: {msg.LockedUntil}. Delivery count: {msg.DeliveryCount}."); }
同时调整计时器逻辑,确保能传递引用更新原消息实例,或用线程安全容器存储最新消息。
固定计时器生命周期:当前
Timer是局部变量,可能被GC回收导致续锁中断。需将Timer保留在类级别变量中,任务完成后手动调用timer.Dispose()释放。缩短续锁间隔并增加容错:网络或服务端延迟可能导致续锁不及时,可将间隔调整为锁时长的1/2(比如5分钟锁→2.5分钟续一次),同时在续锁时捕获
MessageLockLostException,一旦出现就终止任务并处理重试。确保接收器实例一致性:全程使用同一个
ServiceBusReceiver实例,避免其他地方创建新接收器接收同一条消息。若用ServiceBusProcessor,需确认并发配置正确,防止多实例抢消息。
内容的提问来源于stack exchange,提问作者Yuriy Gavrishov
相关产品推荐
相关产品推荐

