How to use Service Bus topics and subscriptions with Ruby

This article describes how to use Service Bus topics and subscriptions from Ruby applications. The scenarios covered include:

  • Creating topics and subscriptions
  • Creating subscription filters
  • Sending messages to a topic
  • Receiving messages from a subscription
  • Deleting topics and subscriptions

Prerequisites

  1. An Azure subscription. To complete this tutorial, you need an Azure account. You can activate your Visual Studio or MSDN subscriber benefits or sign-up for a free account.

  2. Follow steps in the Quickstart: Use the Azure portal to create a Service Bus topic and subscriptions to the topic to create a Service Bus namespace and get the connection string.

    Note

    You will create a topic and a subscription to the topic by using Ruby in this quickstart.

Create a Ruby application

For instructions, see Create a Ruby Application on Azure.

Configure Your application to Use Service Bus

To use Service Bus, download and use the Azure Ruby package, which includes a set of convenience libraries that communicate with the storage REST services.

Use RubyGems to obtain the package

  1. Use a command-line interface such as PowerShell (Windows), Terminal (Mac), or Bash (Unix).
  2. Type "gem install azure" in the command window to install the gem and dependencies.

Import the package

Using your favorite text editor, add the following to the top of the Ruby file in which you intend to use storage:

require "azure"

Set up a Service Bus connection

Use the following code to set the values of namespace, name of the key, key, signer and host:

Azure.configure do |config|
  config.sb_namespace = '<your azure service bus namespace>'
  config.sb_sas_key_name = '<your azure service bus access keyname>'
  config.sb_sas_key = '<your azure service bus access key>'
end
signer = Azure::ServiceBus::Auth::SharedAccessSigner.new
sb_host = "https://#{Azure.sb_namespace}.servicebus.windows.net"

Set the namespace value to the value you created rather than the entire URL. For example, use "yourexamplenamespace", not "yourexamplenamespace.servicebus.windows.net".

Create a topic

The Azure::ServiceBusService object enables you to work with topics. The following code creates an Azure::ServiceBusService object. To create a topic, use the create_topic() method. The following example creates a topic or prints out any errors.

azure_service_bus_service = Azure::ServiceBus::ServiceBusService.new(sb_host, { signer: signer})
begin
  topic = azure_service_bus_service.create_topic("test-topic")
rescue
  puts $!
end

You can also pass an Azure::ServiceBus::Topic object with additional options, which enable you to override default topic settings such as message time to live or maximum queue size. The following example shows setting the maximum queue size to 5 GB and time to live to 1 minute:

topic = Azure::ServiceBus::Topic.new("test-topic")
topic.max_size_in_megabytes = 5120
topic.default_message_time_to_live = "PT1M"

topic = azure_service_bus_service.create_topic(topic)

Create subscriptions

Topic subscriptions are also created with the Azure::ServiceBusService object. Subscriptions are named and can have an optional filter that restricts the set of messages delivered to the subscription's virtual queue.

Subscriptions are persistent. They continue to exist until either they, or the topic they are associated with, are deleted. If your application contains logic to create a subscription, it should first check if the subscription already exists by using the getSubscription method.

Create a subscription with the default (MatchAll) filter

If no filter is specified when a new subscription is created, the MatchAll filter (default) is used. When the MatchAll filter is used, all messages published to the topic are placed in the subscription's virtual queue. The following example creates a subscription named "all-messages" and uses the default MatchAll filter.

subscription = azure_service_bus_service.create_subscription("test-topic", "all-messages")

Create subscriptions with filters

You can also define filters that enable you to specify which messages sent to a topic should show up within a specific subscription.

The most flexible type of filter supported by subscriptions is the Azure::ServiceBus::SqlFilter, which implements a subset of SQL92. SQL filters operate on the properties of the messages that are published to the topic. For more details about the expressions that can be used with a SQL filter, review the SqlFilter syntax.

You can add filters to a subscription by using the create_rule() method of the Azure::ServiceBusService object. This method enables you to add new filters to an existing subscription.

Since the default filter is applied automatically to all new subscriptions, you must first remove the default filter, or the MatchAll overrides any other filters you may specify. You can remove the default rule by using the delete_rule() method on the Azure::ServiceBusService object.

The following example creates a subscription named "high-messages" with an Azure::ServiceBus::SqlFilter that only selects messages that have a custom message_number property greater than 3:

subscription = azure_service_bus_service.create_subscription("test-topic", "high-messages")
azure_service_bus_service.delete_rule("test-topic", "high-messages", "$Default")

rule = Azure::ServiceBus::Rule.new("high-messages-rule")
rule.topic = "test-topic"
rule.subscription = "high-messages"
rule.filter = Azure::ServiceBus::SqlFilter.new({
  :sql_expression => "message_number > 3" })
rule = azure_service_bus_service.create_rule(rule)

Similarly, the following example creates a subscription named low-messages with an Azure::ServiceBus::SqlFilter that only selects messages that have a message_number property less than or equal to 3:

subscription = azure_service_bus_service.create_subscription("test-topic", "low-messages")
azure_service_bus_service.delete_rule("test-topic", "low-messages", "$Default")

rule = Azure::ServiceBus::Rule.new("low-messages-rule")
rule.topic = "test-topic"
rule.subscription = "low-messages"
rule.filter = Azure::ServiceBus::SqlFilter.new({
  :sql_expression => "message_number <= 3" })
rule = azure_service_bus_service.create_rule(rule)

When a message is now sent to test-topic, it is always be delivered to receivers subscribed to the all-messages topic subscription, and selectively delivered to receivers subscribed to the high-messages and low-messages topic subscriptions (depending upon the message content).

Send messages to a topic

To send a message to a Service Bus topic, your application must use the send_topic_message() method on the Azure::ServiceBusService object. Messages sent to Service Bus topics are instances of the Azure::ServiceBus::BrokeredMessage objects. Azure::ServiceBus::BrokeredMessage objects have a set of standard properties (such as label and time_to_live), a dictionary that is used to hold custom application-specific properties, and a body of string data. An application can set the body of the message by passing a string value to the send_topic_message() method and any required standard properties are populated by default values.

The following example demonstrates how to send five test messages to test-topic. The message_number custom property value of each message varies on the iteration of the loop (it determines which subscription receives it):

5.times do |i|
  message = Azure::ServiceBus::BrokeredMessage.new("test message " + i,
    { :message_number => i })
  azure_service_bus_service.send_topic_message("test-topic", message)
end

Service Bus topics support a maximum message size of 256 KB in the Standard tier and 1 MB in the Premium tier. The header, which includes the standard and custom application properties, can have a maximum size of 64 KB. There is no limit on the number of messages held in a topic but there is a cap on the total size of the messages held by a topic. This topic size is defined at creation time, with an upper limit of 5 GB.

Receive messages from a subscription

Messages are received from a subscription using the receive_subscription_message() method on the Azure::ServiceBusService object. By default, messages are read(peak) and locked without deleting it from the subscription. You can read and delete the message from the subscription by setting the peek_lock option to false.

The default behavior makes the reading and deleting a two-stage operation, which also makes it possible to support applications that cannot tolerate missing messages. When Service Bus receives a request, it finds the next message to be consumed, locks it to prevent other consumers receiving it, and then returns it to the application. After the application finishes processing the message (or stores it reliably for future processing), it completes the second stage of the receive process by calling delete_subscription_message() method and providing the message to be deleted as a parameter. The delete_subscription_message() method marks the message as being consumed and remove it from the subscription.

If the :peek_lock parameter is set to false, reading, and deleting the message becomes the simplest model, and works best for scenarios in which an application can tolerate not processing a message when a failure occurs. Consider a scenario in which the consumer issues the receive request and then crashes before processing it. Because Service Bus has marked the message as being consumed, then when the application restarts and begins consuming messages again, it has missed the message that was consumed prior to the crash.

The following example demonstrates how messages can be received and processed using receive_subscription_message(). The example first receives and deletes a message from the low-messages subscription by using :peek_lock set to false, then it receives another message from the high-messages and then deletes the message using delete_subscription_message():

message = azure_service_bus_service.receive_subscription_message(
  "test-topic", "low-messages", { :peek_lock => false })
message = azure_service_bus_service.receive_subscription_message(
  "test-topic", "high-messages")
azure_service_bus_service.delete_subscription_message(message)

How to handle application crashes and unreadable messages

Service Bus provides functionality to help you gracefully recover from errors in your application or difficulties processing a message. If a receiver application is unable to process the message for some reason, then it can call the unlock_subscription_message() method on the Azure::ServiceBusService object. It causes Service Bus to unlock the message within the subscription and make it available to be received again, either by the same consuming application or by another consuming application.

There is also a timeout associated with a message locked within the subscription, and if the application fails to process the message before the lock timeout expires (for example, if the application crashes), then Service Bus unlocks the message automatically and make it available to be received again.

In the event that the application crashes after processing the message but before the delete_subscription_message() method is called, then the message is redelivered to the application when it restarts. It is often called at least once processing; that is, each message is processed at least once but in certain situations the same message may be redelivered. If the scenario cannot tolerate duplicate processing, then application developers should add additional logic to their application to handle duplicate message delivery. This logic is often achieved using the message_id property of the message, which remains constant across delivery attempts.

Delete topics and subscriptions

Topics and subscriptions are persistent, and must be explicitly deleted either through the Azure portal or programmatically. The following example demonstrates how to delete the topic named test-topic.

azure_service_bus_service.delete_topic("test-topic")

Deleting a topic also deletes any subscriptions that are registered with the topic. Subscriptions can also be deleted independently. The following code demonstrates how to delete the subscription named high-messages from the test-topic topic:

azure_service_bus_service.delete_subscription("test-topic", "high-messages")

Next steps

Now that you've learned the basics of Service Bus topics, follow these links to learn more.