我有一个使用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");
}
}
我的问题是:如何禁用此行为?我很高兴交易花费时间,因为这是一个繁重的过程,我从我的网站卸载,这是首先与这个架构的关系。
换句话说,我希望消息不被另一个处理程序接收,而另一个处理程序已经接收并正在处理它,除非有异常且消息返回队列并最终得到重试。
任何想法如何做到这一点?我失踪了什么?
答案 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)