我正在构建一个基于服务总线的应用程序。当我的接收器从服务总线获取消息时,可能需要花费大量时间来处理它,所以我想等待处理,但是如果花费太多时间,则应该取消处理并且消息应该是完成。
这是接收者的代码:
client.OnMessageAsync(async message =>
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("message from api");
try
{
CancellationTokenSource source = new CancellationTokenSource();
source.CancelAfter(TimeSpan.FromSeconds(30));
var task = new Task(() => ProcessServiceBusMessage(message).Wait(), source.Token);
await message.CompleteAsync();
}
catch (Exception ex)
{
errLog.Error(ex.Message + ex.StackTrace);
await message.DeadLetterAsync();
}
}, new OnMessageOptions() { AutoComplete = false, MaxConcurrentCalls = 20, AutoRenewTimeout = new TimeSpan(0, 5, 0) });
正如您所看到的,我在一个任务中启动ProcessServiceBusMessage
函数,我等待它并在30秒后使用CancellationToken
取消任务(如果消息需要超过30秒到完整处理),但它不起作用。
我该如何解决?
编辑:具体来说,任务在30秒后没有被取消,并且立即执行message.CompleteAsync()
,而不等待任务
谢谢。
答案 0 :(得分:2)
问题是你创建了一个任务但没有等待它,所以立即调用CompleteAsync
。
这应该是一种更清洁的方法:
var task = ProcessServiceBusMessage(message);
await Task.WhenAny(task, Task.Delay(timeout));
await message.CompleteAsync();
答案 1 :(得分:0)
您是否要考虑使用Azure存储队列?
默认情况下,邮件被锁定30秒,因此可能存在冲突。在30秒取消发生之前,Service Bus可能会抛出Lock过期的异常