We're seeing some odd behaviour while processing a long-running message on an Azure Service Bus queue. We are renewing the lock as we run over a fairly large dataset and this particular message generally takes around 1 hour to complete. The process works great and runs through to completion, unless it is running over midnight UTC.
Bang on midnight UTC, our process throws an exception:
Microsoft.ServiceBus.Messaging.MessageLockLostException: The lock supplied is invalid. Either the lock expired, or the message has already been removed from the queue.
We are able to reproduce this night after night, and it never happens if we don't run the process over midnight.
Could it be that the message lock "ExpiresAtUtc" timestamp calculation doesn't handle crossing over from one day to another very gracefully?
---- UPDATE ----
Some more information that might help:
The long running process keeps the message from becoming visible again on the queue by calling RenewLock
. When this processing continues over midnight we notice that the message becomes visible on the queue and processing is restarted. The message is not dropped and does not move to the dead letter queue. It's lock simply expires and the message becomes visible on the queue again so it is picked up by a processor and the process is restarted. As long as the process does not cross the boundary of midnight UTC it completes successfully.
Here are snippets of code we're using to connect / enqueue / dequeue from the queues:
Connect to queue:
private QueueClient GetQueue<TMessage>() => QueueClient.CreateFromConnectionString(this.configSection.Value.ConnectionString, typeof(TMessage).Name, ReceiveMode.PeekLock);
Enqueue message:
using (var brokeredMessage = new BrokeredMessage(message) {ContentType = "application/json"})
{
await GetQueue<TMessage>().SendAsync(brokeredMessage).ConfigureAwait(false);
}
Dequeue message:
GetQueue<TMessage>().OnMessageAsync(
async msg =>
{
TMessage body = null;
try
{
body = msg.GetBody<TMessage>();
await handler.HandleMessageAsync(body, msg.RenewLockAsync).ConfigureAwait(false);
await msg.CompleteAsync().ConfigureAwait(false);
}
catch (Exception ex)
{
await msg.AbandonAsync().ConfigureAwait(false);
}
},
new OnMessageOptions
{
AutoComplete = false
}
);
Below is a screenshot of the Azure Service Bus Metrics - Successful Requests, over midnight UTC (I'm in a UTC+1 timezone so that's 1:00 AM where I am) showing how at midnight something affecting the queue happens:
Below is a screenshot of our internal logging, the processing just stops and then starts up again after just over a minute - when the lock expires and the message becomes visible on the queue again so is picked up by the processor: