Azure Service Bus is a fully managed integration message broker. It is a service providing reliable and secure asynchronous transfer of state and data. A service bus is used to connect applications in a loosely coupled way, by using a third party queuing service. Applications can run and do work without being directly reliant on dependencies being available. Using messages as communication improves reliability and scalability of applications in a natural fashion. I will briefly introduce the different entities used in ASB and how they work together.

Azure Service Bus uses a set of entities to build a message topology. The different entities can be combined in different ways resulting in different topologies. There are several usable topologies, depending on the characteristics of the system. The most robust way of combining the entities available is what is referred to as a forwarding topology, which will be the basis of the explanations in this article. Read more about different topologies in Daniel Marbach's series on the topic: https://www.planetgeek.ch/2019/01/07/azure-service-bus-topologies/

Photo by Jerry Zhang / Unsplash

Queues

Queues receive and hold messages ordered and timestamped on arrival. While in the queue messages can have a time to live after which, if not received, it can be deleted. Messages are delivered to consumers on request - in pull mode. Typically a consumer first reads and locks a message (PeekLock) - when locked, the message is made "invisible" and cannot be received by another consumer. After successfully handling the message, the consumer acknowledges this to the queue and the message is deleted.

Messages sent directly to a queue are referred to as commands. Commands are named in imperative form and represent an instruction - e.g."DeleteCustomer". A command is sent to one and only one queue. Both the queue and the command types are owned by a service and are not exposed externally. The service is responsible for the provisioning and management of its own queue. The point is that when interacting directly with a specific queue you are coupled to that queue and should thus be the one responsible for its existence. This is also the main reason why commands should not be used across service boundaries.

Topics & Subscriptions

Topics are shared queues used by multiple producers for messages relevant for multiple receivers. Messages sent to a topic are referred to as events, and sending of events as publishing. Events are named in passed tense and represents a notification of an action that has occurred - e.g. "CustomerWasDeleted". Producers of events does not have any notion of who will receive the events published. Even if the topic is a shared entity, all events has one and only one owner and are published from exactly one service.

A topic can have zero or many independent subscriptions. Each subscription is owned and provisioned by one consumer. Subscriptions express interest in a subset of messages published to the topic. When a message arrives on the topic, a copy is created on each subscription. The subscription then evaluates whether the message fulfills the subscription rules or not. Each consumer can receive the event independently by reading from the subscription.

A problem arises when a consumer is not consuming messages from its subscription - in this case the topic might eventually overflow. This is circumvent using a feature in subscriptions called forwarding. A subscription can configure a queue which all messages should be forwarded to automatically. This way we can have one common topic for all messages, one subscription per consumer, while also completely decoupling the producer from the consumers. If a consumer is not running, no other endpoints will be affected as forwarding from the topic is handled by the infrastructure.

Advanced Features

In addition to the core entities, ASB includes several features under the hood which might be useful in specific scenarios. Scheduled delivery allows a message to be sent to a queue with a time from which it will be available for processing. Batching is supported for both sending and receiving of messages. To reduce the number of remote calls to the service, messages can be sent on a given interval, with messages stored in-memory first. Prefetching enables consumers to fetch multiple messages at once. Transport transactions is a technique where multiple operations are grouped together into one atomic operation which succeeds and fails as one. One example is if you want to send a message as result of handling an incoming message - to reduce the likelihood of duplicate messages, it is possible to group the sending together with the acknowledge of the incoming message. If the sending fails the incoming message will not be completed.

Read more about Azure Service Bus, strengths and drawbacks of different topologies: