具有事务的长期运行作业Azure Service Bus的模式

时间:2015-08-10 23:53:20

标签: c# azure azureservicebus

我想使用Azure Service Bus进行事务处理,但我有一些网络/ API限制的消息,我无法进一步可靠地重构它们,以便在不到5分钟内完成它们 - 最大PeekLock持续时间允许的。

我无法找到任何允许我扩展锁定的API,所以也许还有另一种模式。

一种可能的解决方案:

1)使用现有实现来接收消息。如果从需要长时间运行的事务的主题/队列中获取 - 使用新的ScheduledEnqueueTimeUtc更新消息并发送回服务总线。

myMessage.ScheduledEnqueueTimeUtc = TimeSpan.FromMinutes(actualLockDuration);
serviceBusClient.PublishMessage(topic, myMessage);

2)通过MessageId获取特定消息,并将该新消息标记为完成。

if (oldMessage.LockedUntilUtc > DateTime.UtcNow) {
  var message = FetchMessage(oldMessage.MessageId);
  message.Complete();
} else {
  oldMessage.Complete();
}

第二个想法,在寻找一个API来通过messageId获取消息后 - 我没有看到一个。如果我按序列ID获取,那么我需要一种方法在步骤1之后获取序列ID - 然后我需要重新考虑许多内部系统(大消息处理,消息记录和关联等)。

1 个答案:

答案 0 :(得分:2)

我不知道我是怎么错过这个的。 BrokeredMessage.RenewLock

我在它周围写了一个小的异步包装,直到最长持续时间。

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

}