How to Use Azure AppFabric Service Bus From Ruby
This article provides information on working with the Azure AppFabric Service Bus from the Ruby programming language. This article assumes that you are familiar with Ruby, and have access to the Azure AppFabric labs site. For more information on Ruby, see http://www.ruby-lang.org/. For more information on accessing Azure AppFabric labs, see http://portal.appfabriclabs.com/.
Currently this article is based on the WAZ-AppFabric sample produced by the CAT team and discussed at http://appfabriccat.com/2011/07/using-azure-appfabric-service-bus-from-ruby-apps/. This sample primarily targets AppFabric Queues, however the same basic principals can be applied when accessing other AppFabric Service Bus REST APIs from Ruby.
NOTE: AppFabric Queues are currently in Community Technical Preview, and are only available on the AppFabricLabs.com environment.
AppFabric exposes REST APIs for most service bus operations, however there are some limitations which are described at http://msdn.microsoft.com/en-us/library/gg278338.aspx#BKMK_REST1.
Windows Azure AppFabric Queues
AppFabric queues provide a reliable store for asynchronous messages, similar to MSMQ. Messages can remain in the queue for an indefinite period of time, until read and deleted by the receiving application. Queues also offer the ability to place a transient lock on messages that are being processed, so that if the receiving application fails, the message is placed back in the queue and can be processed when the application restarts or by another instance of the receiving application.
This article, and the associated sample, provides information on using the following operations:
- Authentication
- Queue Management
- Create
- Delete
- Get
- List
- Queue Operations
- Send
- Receive
- Peek-Lock
- Deleted Peeked Messaged
- Unlock Peeked Message
Representational State Transfer (REST)
REST is a vast topic, and far beyond the scope of this article. It can be summarized as an architecture that defines a type of client/server communication where the client interacts with resources on the server that are addressable through a unique URI. Resource interaction is typically performed using standard HTTP verbs (GET, POST, PUT or DELETE). Resources are also typed as a specific MIME type (XML, PNG, Text/Plain, etc.)
For the purposes of this article, REST is a way by which Ruby applications can interact with services provided by the Windows Azure AppFabric Service Bus. An example REST message from the client to receive a message from a queue would appear as follows:
DELETE https://rubytest.servicebus.appfabriclabs.com/testqueue/messages/head?timeout=60 HTTP/1.1
Accept: */*; q=0.5, application/xml
Accept-Encoding: gzip, deflate
Authorization: WRAP access_token="net.windows.servicebus.action=Listen%2cManage%2cSend&http%3a%2f%2fschemas.microsoft.com%2faccesscontrolservice%2f2010%2f07%2fclaims%2fidentityprovider=https%3a%2f%2frubytest-sb.accesscontrol.appfabriclabs.com%2f&Audience=http%3a%2f%2frubytest.servicebus.appfabriclabs.com&ExpiresOn=1306783739&Issuer=https%3a%2f%2frubytest-sb.accesscontrol.appfabriclabs.com%2f&HMACSHA256=ebfBpf%2fCKEoIxEqXzFtImTv2Z8Zk9NhqHvtjB%2fKv8b0%3d"
Content-Length: 0
Host: rubytest.servicebus.appfabriclabs.com
The URI identifying the resource is HTTPS://rubytest.servicebus.appfabriclabs.com/testqueue/messages/head, and the verb used is DELETE. This will receive a message from the queue named ‘testqueue’ and then delete the message after it has been received.
There are several Ruby gems that provide REST functionality, for this article we will be using the rest-client gem. The following is an example of using the generate_request method provided by the rest-gem client to receive a message from a queue named ‘testqueue’. This would result in a REST message such as the one in the previous example.
request = generate_request(:delete, “https://rubytest.servicebus.appfabriclabs.com/testqueue/messages/head?timeout=60”, accessToken, nil, nil)
result = request.execute()
For more information on the rest-client gem, see http://rubygems.org/gems/rest-client.
Getting Started
Prerequisites
- Ruby
- The rest-client gem
- An AppFabric namespace on the AppFabric Labs site
- AppFabric Ruby sample
Installing Ruby
The Ruby language has several different installation packages, depending on the platform you are using. See http://www.ruby-lang.org for guidance.After Ruby has been installed, you can install the rest-client gem by issuing the following command:
gem install rest-client
Create an AppFabric Service Bus
The following steps will guide you through the process of creating an AppFabric Service Bus on the AppFabric Labs.
- Navigate to https://portal.appfabriclabs.com/, and then sign in.
- Select ‘AppFabric Services’ from the bottom left of the page.
- Select ‘New Namespace’ from the ribbon at the top of the page.
- In Available Services, ensure that only Service Bus is selected.
- Enter a namespace, for example RubyQueue.
- Select a region, for example United States (South/Central).
- All other settings can remain as default.
- Click ‘Create Namespace’.
Once the namespace status changes to Active (green), you can begin working with queues within this namespace.
AppFabric Ruby Sample
The stand-alone sample can be downloaded from the AppFabric CAT team blog at http://appfabriccat.com/2011/07/using-azure-appfabric-service-bus-from-ruby-apps/.
Authentication
When accessing an AppFabric queue, you must present a Simple Web Token that authorizes you when using any of the REST APIs. An access token can be obtained by sending a request containing the Issuer and Key values, the scope (your service bus namespace,) to the AppFabric ACS WRAP endpoint. The endpoint will return a token that can be used when calling the service bus REST APIs. An example request to the WRAP endpoint would appear as follows:
POST https://rubytest-sb.accesscontrol.appfabriclabs.com/WRAPv0.9/ HTTP/1.1
Accept: */*; q=0.5, application/xml
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Content-Length: 140
Host: rubytest-sb.accesscontrol.appfabriclabs.com
wrap_name=owner&wrap_password=xwCOTgOHT%2Fw8daI9mhCA8Vm0SlKYPKZojYfYCafsRaU%3D&wrap_scope=http%3A%2F%2Frubytest.servicebus.appfabriclabs.com
The value returned from the WRAP endpoint must be parsed and decoded (URL-encoding) before it can be used. The AccessControl.rb file included in the WAZ-AppFabric sample provides the get_access_token method, which invokes the WRAP endpoint and returns a decoded access token. This file also provides the get_scope helper method, which creates the scope URL needed when requesting an access token.
The following is an example of using the get_scope and get_access_token methods:
scopeUri = WAZ::AppFabric::AccessControl.get_scope(serviceNamespace)
accessToken = WAZ::AppFabric::AccessControl.get_access_token(serviceNamespace, scopeUri, serviceIdentityName, serviceIdentityPassword)
Queue Management
The queue management REST APIs provide functionality to create, inspect, list, and delete queues within a service bus namespace. The WAZ-AppFabric sample encapsulates the calls to the REST APIs in the QueueManagement.rb file, which exposes queue management functionality through the methods in the WAZ::AppFabric::QueueMagagement class. The operations and matching methods are described in the following table.
Management Operation |
Description |
Method |
Create |
Creates a new queue |
create_queue(serviceNamespace, queueName, accessToken) |
Delete |
Deletes an existing queue |
delete_queue(serviceNamespace, queueName, accessToken) |
Get |
Returns information on an existing queue |
get_queue(serviceNamespace, queueName, accessToken) |
List |
List all queues within the namespace |
list_queues(serviceNamespace, accessToken) |
The following example creates, and then deletes a queue named ‘testqueue’:
createQueueResponse = WAZ::AppFabric::QueueManagement.create_queue(serviceNamespace, “testqueue”, accessToken)
deleteQueueResponse = WAZ::AppFabric::QueueManagement.delete_queue(serviceNamespace, “testqueue”, accessToken)
Queue Operations
Once created, you can use REST to send, receive, and delete messages from a queue. The WAZ-Appfabric sample encapsulates the REST APIs to accomplish these tasks in the QueueClient.rb file, which exposes these operations through the methods in the WAZ::AppFabric::QueueClient class. The operations and matching methods are described in the following table.
Queue Operation |
Description |
Method |
Send |
Stores a message into a queue |
send(serviceNamespace, queueName, accessToken, content) |
Receive |
Receives a message from a queue, and then deletes the message |
receive(serviceNamespace, queueName, accessToken) |
Peek-lock |
Receives a message from a queue, and then places a lock on the message
|
peeklock(serviceNamespace, queueName, accessToken) |
Delete locked message |
Deletes a message locked by peek-lock |
deletePeekedMessage(serviceNamespace, queueName, accessToken, messageId, lockId) |
Remove lock |
Removes a lock placed on a message by peek-lock |
unlockPeekedMessage(serviceNamespace, queueName, accessToken, messageId, lockId) |
The receive operation is straightforward, and is generally used when the receiving application receives and processes the application as one atomic unit of work. If there is a risk that the receiving application may fail and lose the message, such as an application that passes the message to a separate process for validation, peek-lock is more desirable, as it will place the message back into the queue if the receiving application does not explicitly delete the message within the timeout period. This behavior allows you to continuously retry processing of the message until you explicitly confirm processing by deleting the message; peek-lock and delete locked message can be used to provides a pseudo-transactional receive process.
The following is an example of sending, peek-locking, and then deleting a message to a queue named ‘testqueue’:
sendMessageResponse = WAZ::AppFabric::QueueClient.send(serviceNamespace, “testqueue”, accessToken, 'Hello, from Ruby!')
peeklockMessageResponse = WAZ::AppFabric::QueueClient.peeklock(serviceNamespace, “testqueue”, accessToken)
messageId = peeklockMessageResponse.headers[:x_ms_message_id]
lockId = peeklockMessageResponse.headers[:x_ms_lock_id]
deletelockedMessageResponse = WAZ::AppFabric::QueueClient.deletePeekedMessage(serviceNamespace, “testqueue”, accessToken, messageId, lockId)
As can be seen in this example, deleting a locked message requires information obtained from the request to peek-lock the message; specifically the message ID and lock ID.