Search code examples
azureazureservicebus

Autotmatically renewing locks correctly on Azure Service Bus


So I'm trying to understand service bus timings - especially how the locks works. One can choose to manually call CompleteAsync which is what we're doing. It could also be the case that the processing takes some time. In these cases we want to make sure we don't get unnecessary MessageLockLostException.

Seems there are a couple of numbers to relate to:

  • Lock duration (found in Azure Portal on the Service Bus, currently set to 1 minute which is think is default)
  • AutoRenewTimeout (property on OnMessageOptions, currently set to 1 minute)
  • AutoComplete (property on OnMessageOptions, currently set to false)

Assuming the message processing is running for around 2 minutes, and then either succeeds or crashes (doesn't matter which case for now). Let's say this is the normal scenario, so this means that processing takes roughly 2 minutes for each message.

Also, it's indeed a queue and not a topic. And we only have one consumer that asynchronously processes the messages with MaxConcurrentCalls set to 100. We're using OnMessageAsync with ReceiveMode.PeekLock.

What should my settings now be as a single consumer to robustly process all messages?

I'm thinking that leaving Lock duration to 1 minute would be fine, as that's the default, and set my AutoRenewTimeout to 5 minutes for safety, because as I've understood this value should be the maximum time it takes to process a message (at least according to this answer). Performance is not critical for this system, so I'm resonating as that leaving a message locked for some unnecessary 1, 2 or 3 minutes is not evil, as long as we don't get LockedException because these give no real value.

This thread and this thread gives great examples of how to manually renew the locks, but I thought there is a way to automatically renew the locks.


Solution

  • What should my settings now be as a single consumer to robustly process all messages?

    Aside from LockDuration, MaxConcurrentCalls, AutoRenewTimeout and AutoComplete, there are some configurations of the Azure Service Bus client you might want to look into.

    For example, don't create a single client with MaxConcurrentCalls set to 100, but create multiple clients with total concurrency level distributed among them. Note that you'd want to use different MessagingFactory instances to create those clients to ensure you have more than a single "pipe" to receive messages. And even with that, it would be way better to scale out and have competing consumers rather than having a single consumer handling all the load.

    Now back to the settings. If your normal processing time is 2 minutes, it's better to set MaxLockDuration on the entities to this time and not 1 minute. This will remove unnecessary lock extension calls to the broker and eliminate MessageLockLostException.

    Also, keep in mind that AutoRenewTimeout operation is based on the client, not the broker, and therefore not guaranteed. You will run into cases where lock will be lost even though the AutoRenewTimeout time has not elapsed yet.

    AutoRenewTimeout should always be set to longer than MaxLockDuration as it will be counterproductive to have them equal. Have it somewhat larger than MaxLockDuration as this is clients' "insurance" that when processing takes longer than MaxLockDuration, message lock won't be lost. Having those two equal is, in essence, disables this fallback.