[英]Pattern for long running jobs Azure Service Bus with transactions
I want to use transaction with Azure Service Bus but I have some messages that are network/API bound and I simply can't reliably refactor them any further to make them complete in less than 5 minutes - the max PeekLock duration allowed.我想将事务与 Azure 服务总线一起使用,但我有一些网络/API 绑定的消息,我无法可靠地进一步重构它们以使它们在不到 5 分钟的时间内完成 - 允许的最大 PeekLock 持续时间。
I can't find any API that allows me to extend a lock, so maybe there is another pattern out there.我找不到任何允许我扩展锁的 API,所以也许还有另一种模式。
One possible solution:一种可能的解决方案:
1) Use existing implementation for receiving messages. 1) 使用现有的实现来接收消息。 If fetching from topic/queue that requires long running transactions - update the message with a new ScheduledEnqueueTimeUtc and send back to the service bus.
如果从需要长时间运行的事务的主题/队列中获取 - 使用新的 ScheduledEnqueueTimeUtc 更新消息并将其发送回服务总线。
myMessage.ScheduledEnqueueTimeUtc = TimeSpan.FromMinutes(actualLockDuration);
serviceBusClient.PublishMessage(topic, myMessage);
2) Fetch the specific message by MessageId and mark that new message as complete. 2) 通过 MessageId 获取特定消息并将该新消息标记为完成。
if (oldMessage.LockedUntilUtc > DateTime.UtcNow) {
var message = FetchMessage(oldMessage.MessageId);
message.Complete();
} else {
oldMessage.Complete();
}
On second thought, after looking for an API to fetch a message by messageId - I don't see one.再想一想,在寻找通过 messageId 获取消息的 API 之后 - 我没有看到。 If I fetch by Sequence Id then I need a way to get the Sequence Id after step 1 - then I need to rethink a number of internal systems (large message handling, message logging and correlation, etc.)
如果我通过 Sequence Id 获取,那么我需要一种在步骤 1 之后获取 Sequence Id 的方法 - 那么我需要重新考虑一些内部系统(大型消息处理、消息记录和关联等)
I don't know how I missed this.我不知道我是怎么错过这个的。
BrokeredMessage.RenewLock
I wrote a little async wrapper around it to renew until a maximum duration.我在它周围写了一个小的异步包装器来更新直到最大持续时间。
public static async Task<ProcessMessageReturn> RenewLockAfter(this Task<ProcessMessageReturn> processTask, BrokeredMessage message, int maxDuration)
{
var ss = new SemaphoreSlim(2);
var startTime = DateTime.UtcNow;
var trackedTasks = new List<Task> {processTask};
var timeoutCancellationTokenSource = new CancellationTokenSource();
while (true)
{
ss.Wait(timeoutCancellationTokenSource.Token);
if (startTime.AddMinutes(maxDuration) < DateTime.UtcNow)
{
var task = Task.Run(async () =>
{
await Task.Delay(TimeSpan.FromTicks(message.LockedUntilUtc.Ticks - DateTime.UtcNow.AddSeconds(30).Ticks), timeoutCancellationTokenSource.Token);
await message.RenewLockAsync();
ss.Release();
}, timeoutCancellationTokenSource.Token);
trackedTasks.Add(task);
}
var completedTask = await Task.WhenAny(trackedTasks);
if (completedTask != processTask) continue;
timeoutCancellationTokenSource.Cancel();
return processTask.Result;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.