操作需要时间时重试消息

时间:2015-03-12 02:14:03

标签: azure azureservicebus nimbus

我有一个使用Azure ServiceBus的消息传递系统,但我在其上使用了Nimbus。我有一个端点,它将命令发送到另一个端点,并且另一端的处理程序类将其拾取,所以它一切正常。

当操作花费时间大约超过20秒左右时,处理程序会获得另一个'用相同的消息打电话。看起来Nimbus正在重试已经由处理程序的另一个(甚至是同一个)实例处理的消息,我没有看到任何异常被抛出,我可以使用以下处理程序轻松地重复这个:

public class Synchronizer : IHandleCommand<RequestSynchronization>
{
    public async Task Handle(RequestSynchronization synchronizeInfo)
    {
        Console.WriteLine("Received Synchronization");

        await Task.Delay(TimeSpan.FromSeconds(30)); //Simulate long running process

        Console.WriteLine("Got through first timeout");

        await Task.Delay(TimeSpan.FromSeconds(30)); //Simulate another long running process

        Console.WriteLine("Got through second timeout");
    }
}

我的问题是:如何禁用此行为?我很高兴交易花费时间,因为这是一个繁重的过程,我从我的网站卸载,这是首先与这个架构的关系。

换句话说,我希望消息不被另一个处理程序接收,而另一个处理程序已经接收并正在处理它,除非有异常且消息返回队列并最终得到重试。

任何想法如何做到这一点?我失踪了什么?

2 个答案:

答案 0 :(得分:2)

默认情况下,ASB / WSB会为您提供30秒的消息锁定。这个想法是你从队列的头部弹出BrokeredMessage但是必须在锁定超时内的.Complete()或.Abandon()消息。

如果您不这样做,服务总线会认为您已崩溃或以其他方式失败,它会将该消息返回队列进行重新处理。

您有几个选择:

1)在你的处理程序上实现ILongRunningHandler。 Nimbus将关注剩余的锁定时间并自动更新您的消息锁定。警告:无论您续订多少次,ASB / WSB支持的最长邮件锁定时间都是五分钟,因此如果您的处理程序需要的时间超过您可能需要的选项#2。

public class Synchronizer : IHandleCommand<RequestSynchronization>, ILongRunningTask
{
    public async Task Handle(RequestSynchronization synchronizeInfo)
    {
        Console.WriteLine("Received Synchronization");

        await Task.Delay(TimeSpan.FromSeconds(30)); //Simulate long running process

        Console.WriteLine("Got through first timeout");

        await Task.Delay(TimeSpan.FromSeconds(30)); //Simulate another long running process

        Console.WriteLine("Got through second timeout");
    }
}

2)在你的处理程序中,调用Task.Run(()=&gt; SomeService(yourMessage))并返回。如果您这样做,请注意依赖项的生命周期范围,如果您的处理程序采用任何依赖项。如果你需要一个IFoo,那就依赖一个Func&gt; (或等同于你的容器)并在你的处理任务中解决这个问题。

public class Synchronizer : IHandleCommand<RequestSynchronization>
{
    private readonly Func<Owned<IFoo>> fooFunc;

    public Synchronizer(Func<Owned<IFoo>> fooFunc)
    {
        _fooFunc = fooFunc;
    }

    public async Task Handle(RequestSynchronization synchronizeInfo)
    {
        // don't await!
        Task.Run(() => {
            using (var foo = _fooFunc())
            {
              Console.WriteLine("Received Synchronization");

              await Task.Delay(TimeSpan.FromSeconds(30)); //Simulate long running process

              Console.WriteLine("Got through first timeout");

              await Task.Delay(TimeSpan.FromSeconds(30)); //Simulate another long running process

              Console.WriteLine("Got through second timeout");
            }

        });
    }
}

答案 1 :(得分:0)