In Azure Service Bus, you can schedule a message to deliver at a later time, but you can also defer a message until a later time.
Scheduled Versus Deferred Messages
The difference here is subtle, but important: when you schedule a message, you’re telling the Service Bus to deliver that message at a time of your choosing, when you defer a message, you telling the Service Bus to hang onto a message that has been sent, until such time as you’re ready to receive it.
Why Would you Defer a Message?
The idea here is that you are not ready for the message – but you don’t want to hold up the queue. In this respect, it’s a little like the dead letter concept; that is, there is a message that’s essentially holding up the queue – however, in this case, there’s nothing wrong with the message itself.
Let’s imagine that we receive a message that a sales order has been created – we go to get the customer information for the sales order, and we find that the customer has yet to be created (such things are possible when you start engaging in eventually consistent systems): in this case, you could defer the message, and come back to it when the customer has been created.
Some Code – How to Defer a Message
Deferring a message is actually very simple:
var messageReceiver = new MessageReceiver(connectionString, QUEUE_NAME, ReceiveMode.PeekLock); var message = await messageReceiver.ReceiveAsync(); var sequenceNumber = message.SystemProperties.SequenceNumber; await messageReceiver.DeferAsync(message.SystemProperties.LockToken);
There’s three important concepts here:
1. The sequence number is very important: without it, the message is effectively lost; that’s because of (2)
2. You can receive a message after this, and you will never see the deferred message again until you purposely receive it, which brings us to (3)
3. To retrieve this message, you must explicitly ask for it.
To receive the deferred message you simply pass in the sequence number:
var messageReceiver = new MessageReceiver(connectionString, QUEUE_NAME, ReceiveMode.PeekLock); var message = await messageReceiver.ReceiveDeferredMessageAsync(sequenceNumber); await messageReceiver.CompleteAsync(message.SystemProperties.LockToken);
The deferred message will never time out. Messages have a “Time to Live”, after which they get moved to the Dead Letter Queue; but once a message is deferred, it will live forever, and must be received to remove it.