SMQueue makes writing Ruby clients for message queues almost trivially easy. It has adaptors for Spread, Stomp, and Stdio — which is handy, because that message queue I set up a few weeks back speaks Stomp, and I'm rather fond of Ruby.
Installing SMQueue
The upstream SMQueue repository doesn't have a way to produce a gem yet, so there are two options: drop it into vendor/gems/smqueue in your project, or build a gem from my fork. I went with the latter.
Clone my repository — you'll find a gemspec ready to go. The whole process looks like this:
git clone http://barkingiguana.com/~craig/smqueue.git
cd smqueue
gem build smqueue.gemspec
sudo gem install ./smqueue-0.1.0.gem
I'm told that when SMQueue does get an official gem release it'll start at 0.2.0, so having 0.1.0 installed won't cause any clashes.
Note: I've removed the Spread adaptor from my branch because I don't have a working Spread client on my system and SMQueue won't load without one. I'm sure that'll be sorted in a future release.
Assumptions
For this article I'm assuming you have a working Ruby 1.8.6 install and a local ActiveMQ instance with the Stomp connector enabled. Adjust the code accordingly if your setup differs.
A Simple Producer
Let's start with a contrived example: put an ascending number onto a queue roughly every second. A good source for ascending numbers is the current time as seconds since the epoch — easy to get in Ruby:
>> Time.now.to_i
=> 1230602445
>> Time.now.to_i
=> 1230602446
>> Time.now.to_i
=> 1230602447
Wrap it in a loop with a one-second sleep and you've got a steady stream:
>> loop do
?> puts Time.now.to_i
>> sleep 1
>> end
1230602557
1230602558
1230602559
Easy enough on STDOUT, but how do we get these into a queue? Bring in SMQueue, create a client, and push the numbers on:
require 'rubygems'
require 'smqueue'
queue = SMQueue(
:name => "/queue/numbers.ascending",
:host => "localhost",
:adapter => :StompAdapter
)
loop do
number = Time.now.to_i
puts "Sending #{number}"
queue.puts number.to_yaml
sleep 1
end
Paste this into a terminal to kick off the producer. You should see a steady stream of output — about one message per second.
cat > producer.rb < "/queue/numbers.ascending",
:host => "localhost",
:adapter => :StompAdapter
)
loop do
number = Time.now.to_i
puts "Sending #{number}"
queue.puts number.to_yaml
sleep 1
end
EOF
ruby producer.rb
A Simple Consumer
With the producer running, let's write a consumer that takes each message and converts it back into a human-readable time. It's a pointless task, but it shows just how little code is needed.
require 'rubygems'
require 'smqueue'
require 'yaml'
queue = SMQueue(
:name => "/queue/numbers.ascending",
:host => "localhost",
:adapter => :StompAdapter
)
queue.get do |message|
number = YAML.parse(message.body).transform
time = Time.at(number)
puts "Got #{number} which is #{time}"
end
Let's walk through the important bits.
We tell the queue we want to receive messages:
queue.get do |message|
The producer serialised each number as YAML, so we parse and transform it back:
number = YAML.parse(message.body).transform
Then we convert the number to a time and print both:
time = Time.at(number)
puts "Got #{number} which is #{time}"
Run this to start the consumer:
cat > consumer.rb < "/queue/numbers.ascending",
:host => "localhost",
:adapter => :StompAdapter
)
queue.get do |message|
number = YAML.parse(message.body).transform
time = Time.at(number)
puts "Got #{number} which is #{time}"
end
EOF
ruby consumer.rb
For each message the producer creates, you should see your consumer print a line to the screen. That's all there is to it.