Azure 操作需要时间时重试的消息

Azure 操作需要时间时重试的消息,azure,azureservicebus,nimbus,Azure,Azureservicebus,Nimbus,我有一个使用Azure ServiceBus的消息传递系统,但除此之外我还使用了Nimbus。我有一个端点,它向另一个端点发送命令,另一端的处理程序类在某一点接收命令,所以一切正常 当操作需要时间时,大约超过20秒左右,处理程序会收到带有相同消息的“另一个”调用。看起来Nimbus正在重试处理程序的另一个(甚至是同一个)实例已经在处理的消息,我没有看到任何异常被抛出,我可以使用以下处理程序轻松地重新编程: public class Synchronizer : IHandleCommand<

我有一个使用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");
    }
}
公共类同步器:IHandleCommand
{
公共异步任务句柄(RequestSynchronization synchronizeInfo)
{
Console.WriteLine(“接收到的同步”);
wait Task.Delay(TimeSpan.FromSeconds(30));//模拟长时间运行的进程
WriteLine(“通过第一次超时”);
wait Task.Delay(TimeSpan.FromSeconds(30));//模拟另一个长时间运行的进程
WriteLine(“通过第二次超时”);
}
}
我的问题是:如何禁用此行为?我很高兴交易需要时间,因为这是一个繁重的过程,我已经从我的网站上卸载了,这是使用这种架构的第一点

换句话说,我希望在另一个处理程序已经拾取并正在处理该消息时,该消息不会被另一个处理程序拾取,除非出现异常,该消息返回队列并最终被拾取以进行重试


有什么办法吗?我遗漏了什么吗?

我想您正在这里寻找代码:

默认情况下,ASB/WSB会给您30秒的消息锁定。其思想是从队列的头部弹出一条代理消息,但必须在锁定超时时间内完成.Complete()或.放弃()该消息

如果您不这样做,服务总线将假定您已崩溃或以其他方式失败,并将该消息返回队列以重新处理

您有两个选择:

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

公共类同步器:IHandleCommand、ILongRunningTask
{
公共异步任务句柄(RequestSynchronization synchronizeInfo)
{
Console.WriteLine(“接收到的同步”);
wait Task.Delay(TimeSpan.FromSeconds(30));//模拟长时间运行的进程
WriteLine(“通过第一次超时”);
wait Task.Delay(TimeSpan.FromSeconds(30));//模拟另一个长时间运行的进程
WriteLine(“通过第二次超时”);
}
}
2) 在处理程序中,调用任务。运行(()=>SomeService(yourMessage))并返回。如果您这样做,那么如果您的处理程序接受任何依赖项,请注意依赖项的生命周期范围。如果需要IFoo,请获取对Func>的依赖关系(或取决于容器的等效关系),并在处理任务中解决该问题

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");
            }

        });
    }
}
公共类同步器:IHandleCommand
{
私有只读Func fooFunc;
公共同步器(Func-fooFunc)
{
_fooFunc=fooFunc;
}
公共异步任务句柄(RequestSynchronization synchronizeInfo)
{
//不要等待!
Task.Run(()=>{
使用(var foo=\u fooFunc())
{
Console.WriteLine(“接收到的同步”);
wait Task.Delay(TimeSpan.FromSeconds(30));//模拟长时间运行的进程
WriteLine(“通过第一次超时”);
wait Task.Delay(TimeSpan.FromSeconds(30));//模拟另一个长时间运行的进程
WriteLine(“通过第二次超时”);
}
});
}
}

有趣-默认锁定超时应为1分钟。我不熟悉Nimbus(从他们的网站上看,这需要一点挖掘),但是你是如何从队列中阅读的?您可以在此处增加锁超时,也可以通过
BrokeredMessage.RenewLock()
更新锁。
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");
            }

        });
    }
}