Rescheduling an Azure service bus message using the Azure service bus client library for .NET

Henrique Fernandes
Villa Plus Engineering
4 min readMar 4, 2024

The Azure Service Bus allows for the development of event-driven applications that take advantage of asynchronous messaging patterns using a highly-reliable service to broker messages between producers and consumers. It provides flexible, brokered messaging between client and server, along with structured FIFO messaging and publish/subscribe capabilities.

Microsoft’s Azure.Messaging.ServiceBus NuGet package is the .NET library that allows the integration of .NET projects with Azure Service Buses by providing classes, methods and properties that can be used — with a high degree of customisation — to interact with many elements of Azure’s service buses, such as queues, topics, subscriptions and messages, to name a few.

The problem

There may be some reasons why we would not want a service bus message to be processed immediately. For example, if a certain service or database connection is faulted, we may want to delay its processing, to avoid ineffectual retries and the potential placement of the message on the dead-letter queue. Or maybe we want all of the messages to be processed at the same time because of some business logic or other requirement.

In our particular case, we wanted messages of a certain type to be processed under a specified schedule, such that we could control the “active” hours when clients or operations team members might receive an email sent by an automatic function. There is — at the time of this article’s writing — no way to configure such behaviour in Azure portal, which means that we had to take the programmatical approach.

Solution part 1 — It’s schedule time!

In order to process the service bus messages, we set up an Azure function with a ServiceBusTrigger trigger listening to a specific subscription inside a topic. Then, when a message is received, one of the first things that we need to do is to check if we are inside the “active” schedule time: If the message is within the “active” time, then we execute the normal message processing. If, on the other hand, the message is being executed outside of the “active” schedule time, we want a different flow to be executed, I.e. one where the message gets rescheduled to the next available “active” time.

if (_messageScheduler.IsDateTimeInScheduleTime())
{
await _messageProcessingService.ProcessAsync(message);
}
else
{
await _messageScheduler.RescheduleMessageAsync(message);
}

The IsDateTimeInScheduleTime method checks the current date and time and compares it with a configured set of values (I.e. the “active” schedule). This is what the configuration would look like if the “active” schedule was on Tuesday only, from 9h to 18h:

{
// DayOfWeek codification
// 0 - Sunday, 1 - Monday, 2 - Tuesday, 3 -Wednesday, 4 - Thursday, 5 - Friday, 6 - Saturday
"ScheduledConfigurations": [
{
"DayOfWeek": 2,
"StartTime": 9,
"EndTime": 18
}
]
}

Solution part 2 — Hitting the snooze button

The second part of the solution consists of actually changing the scheduled enqueue time of the message and sending it again to the same queue or a totally different queue. In our architecture we decided to send it to a different queue but we could have used the same one. The RescheduleMessageAsync method looks something like this:

public async Task ScheduleMessage(string originalMessage)
{
await using var client = new ServiceBusClient(_serviceBusConfigurations.ServiceBusConnectionString);
ServiceBusSender sender = client.CreateSender(_serviceBusConfigurations.QueueName);
ServiceBusMessage rescheduledMessage = new ServiceBusMessage(originalMessage);
rescheduledMessage.ScheduledEnqueueTime = SetRescheduledTime();
rescheduledMessage.Subject = _serviceBusConfigurations.FilterSubjectName;
await sender.SendMessageAsync(rescheduledMessage);
}

After configuring the ServiceBusClient and ServiceBusSender, we create a new message that is a copy of the original one, assign it a Subject to be properly queued on another queue and assign it the desired new time of processing — ScheduledEnqueueTime. The SetRescheduledTime method uses the same configuration as described on part 1 to know when the next “active” schedule time is and returns a DateTimeOffset type.

ScheduledEnqueueTime important notes

This property gets or sets the date and time in UTC at which the message will be enqueued. This property returns the time in UTC; when setting the property, the supplied DateTime value must also be in UTC. Message enqueuing time does not mean that the message will be sent at the same time. It will get enqueued, but the actual sending time depends on the queue’s workload and its state.

Summary

In this article we briefly went through the solution that we have developed to reschedule an Azure service bus message instead of processing it immediately. In our particular case it came as a business requirement but the same logic can be followed to handle processing errors. While the Azure portal provides a great way to thoroughly configure most service bus elements, custom behaviour may need to be implemented programmatically. And the Azure Service Bus client library for .NET allowed us to do just that (and stop time-sensitive emails from being sent outside of business hours).

--

--