One of the requirements for our messaging system is to be able to build a system to process messages and either
- Have a default handler and then add custom handlers as and when they are required without needing to recode the main system.
- Be notified if a message is put onto a topic and there isn’t a process to handle the message.
In RabbitMQ this is relatively straight forward and requires creating an alternate-exchange, adding it as a property to your main exchange and then creating a queue to service the alternate-exchange
IDictionary<String, Object> args2 = new Dictionary<String, Object>();
args2.Add("alternate-exchange", alternateExchangeName);
channel.ExchangeDeclare(mainExchangeName, "direct", false, false, args2);
channel.ExchangeDeclare(alternateExchangeName, "fanout");
// Adds a queue bound to the unhandled messages exchange
channel.QueueDeclare(unroutedMessagesQueueName, true, false, false, null);
channel.QueueBind(unroutedMessagesQueueName, alternateExchangeName, "");
Now when a message is published on the main exchange and there is no subscription to handle the message, then the message will automatically appear on the unrouted message queue. This solution will solve both the scenarios we were looking for.
I was interested however understanding how to do this in the Azure Service Bus and whilst it is possible isn’t not as straight forward and will require some code to setup. Topics can be configured to throw an exception if there is no subscription available to process the message when the message is sent. So When the topic is created it needs to be configured to enable this exception to be thrown.
NamespaceManager namespaceManager =
NamespaceManager.CreateFromConnectionString(_ConnectionString);
TopicDescription td = new TopicDescription(topic)
{
EnableFilteringMessagesBeforePublishing = true
};
await namespaceManager.CreateTopicAsync(td);
Now when a message is sent we need to handle the exception and do something with the message. This is the difference between RabbitMQ and Service Bus. In RabbitMQ the message will automatically end up in the unhandled message queue. In service bus we will need to actually add it to the unhandled message queue when the message is sent. This means that at each message producer, the code will need to handle the exception:
try
{
client.Send(message);
}
catch(NoMatchingSubscriptionException ex)
{
// Do something here to process the unhandled message
// Probably put it on an unhandled message queue
}
Note, however, that if you had a subscription that was a catch all (for example logging all the messages) then unhandled messages would not appear as they are already being handled by the catch all subscription.