14

有人可以提供有关使用 Azure 服务总线 OnMessageOptions.AutoRenewTimeout http://msdn.microsoft.com/en-us/library/microsoft.servicebus.messaging.onmessageoptions.autorenewtimeout.aspx的更多指导吗

因为我没有找到关于此选项的太多文档,并且想知道这是否是更新消息锁的正确方法

我的用例:

1) Message Processing Queue 的 Lock Duration 为 5 分钟(允许的最大值)

2) 消息处理器使用 OnMessageAsync 消息泵从队列中读取(使用 ReceiveMode.PeekLock)长时间运行的处理可能需要长达 10 分钟来处理消息,然后才能手动调用 msg.CompleteAsync

3)我希望消息处理器自动更新它的锁定,直到它预计完成处理的时间(约 10 分钟)。如果在那段时间之后它还没有完成,锁应该被自动释放。

谢谢

- 更新

我从来没有得到更多关于 AutoRenewTimeout 的指导。我最终使用了一个自定义 MessageLock 类,该类根据计时器自动更新消息锁。

请参阅要点 - https://gist.github.com/Soopster/dd0fbd754a65fc5edfa9

4

3 回答 3

14

要处理长消息处理,您应该设置AutoRenewTimeout== 10 分钟(在您的情况下)。这意味着每次锁定都会在这 10 分钟内更新LockDuration

因此,例如,如果您LockDuration是 3 分钟和AutoRenewTimeout10 分钟,那么每 3 分钟的锁定将自动更新(3 分钟、6 分钟和 9 分钟后),并且在消息被消费后 12 分钟后锁定将自动释放。

于 2016-03-17T03:57:26.740 回答
1

我的工人也有同样的问题。即使消息已成功处理,由于处理时间长,服务总线也会取消对其应用的锁定,并且消息可以再次接收。其他可用的工作人员接收此消息并再次开始处理它。如果我错了,请纠正我,但是在您的情况下, OnMessageAsync 将使用相同的消息多次调用,并且您最终将同时处理多个任务。在进程结束时,将抛出 MessageLockLost 异常,因为消息没有应用锁。我用下面的代码解决了这个问题。

_requestQueueClient.OnMessage(
            requestMessage =>
            {
                RenewMessageLock(requestMessage);
                var messageLockTimer = new System.Timers.Timer(TimeSpan.FromSeconds(290));
                messageLockTimer.Elapsed += (source, e) =>
                {
                    RenewMessageLock(requestMessage);
                };
                messageLockTimer.AutoReset = false; // by deffault is true
                messageLockTimer.Start();

                /* ----- handle requestMessage ----- */

                requestMessage.Complete();

                messageLockTimer.Stop();
            }

 private void RenewMessageLock(BrokeredMessage requestMessage)
    {
        try
        {
            requestMessage.RenewLock();
        }
        catch (Exception exception)
        {

        }
    }

自从你的帖子以来,有几个坐骑,也许你已经解决了这个问题,所以你能分享你的解决方案吗?

于 2015-04-15T08:09:42.417 回答
1

根据我个人的喜好,OnMessageOptions.AutoRenewTimeout 是一个有点过于粗糙的续租选项。如果将其设置为 10 分钟并且无论出于何种原因消息仅在 10 分 5 秒后为 .Complete(),则该消息将再次出现在消息队列中,将被下一个备用 Worker 和整个处理将再次执行。这是一种浪费,而且还会阻止 Worker 执行其他未处理的请求。

要解决此问题:

  1. 更改您的 Worker 进程以验证它刚刚从消息队列接收到的项目是否尚未处理。查找存储在某处的成功/失败结果。如果已经处理,请调用 BrokeredMessage.Complete() 并继续等待下一个项目弹出。

  2. 定期调用 BrokeredMessage.RenewLock() - 在锁过期之前,例如每 10 秒 - 并将 OnMessageOptions.AutoRenewTimeout 设置为 TimeSpan.Zero。因此,如果处理一个项目的 Worker 崩溃了,Message 将更快地返回到 MessageQueue 中,并被下一个备用 Worker 拾取。

于 2019-04-28T19:08:35.340 回答