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:
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.
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.