Writing Ruby/Stomp clients with SMQueue
SMQueue makes writing Ruby clients that interact with message queues pretty much trivial. It's got adaptors for Spread, Stomp and Stdio. Which is pretty handy 'cause that message queue I setup a few weeks back talks Stomp and I'm quite into Ruby.
Installing SMQueue
The origin SMQueue repository doesn't yet have a way of producing a gem so there are two ways to install SMQueue: add a vendor/gems/smqueue directory to your project or build a gem from my SMQueue repository. Oddly enough, I've gone with the later approach.
Clone my repository and you'll see there's a gemspec file. You can use that to build a gem using the gem
command. The whole process looks something 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 reliably informed that when SMQueue does build into a gem it'll start at 0.2.0 so having a 0.1.0 installed wont cause any clashes.
Note that I've removed the Spread adaptor from my branch because I don't have a working spread client on my system and I can't get SMQueue to load without one. I'm sure that'll be fixed in a future release.
Basic assumptions
I've made the following assumptions for this article: that you have a working Ruby 1.8.6 install, and that you have an ActiveMQ instance running locally with the Stomp connector enabled. You'll have to change the code to match your environment if these assumptions aren't correct.
A simple producer
Now that SMQueue is installed I'll take a contrived example and implement it. Let's say I want an ascending number to be put onto a queue roughly every second. A pretty good source for these numbers might be the current time represented as seconds from the epoch. Handily I can get just such a number really easily in Ruby.
>> Time.now.to_i
=> 1230602445
>> Time.now.to_i
=> 1230602446
>> Time.now.to_i
=> 1230602447
I can get a number to be output every second by wrapping it in a loop and sleeping a second at the end of the loop.
>> loop do
?> puts Time.now.to_i
>> sleep 1
>> end
1230602557
1230602558
1230602559
Easy enough to get them on STDOUT, but how do I get them into a queue? Well, for that I need to start using the SMQueue library, create a client for the queue, and put a representation of the number onto the queue.
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 the below into a terminal somewhere to kick off the producer. You should see a steady stream of output - about one message a second - saying that it's sending a number.
cat > producer.rb <<EOF
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
EOF
ruby producer.rb
A simple consumer
Now that I have a simple producer running, l'll take the messages and convert them back into a time. It's a pretty pointless task for the consumer, but it'll show just how easy it is to write one.
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 go through the important parts in more detail.
I tell the queue that I want to capture messages.
queue.get do |message|
The producer put the messages in as YAML so I need to transform them back to their native state. I can do this by parsing the YAML then transforming it.
number = YAML.parse(message.body).transform
Now that I have the number, I convert it to a time and output both the original number and the calculated time.
time = Time.at(number)
puts "Got #{number} which is #{time}"
That's pretty much it... run the below code to start running the consumer.
cat > consumer.rb <<EOF
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
EOF
ruby consumer.rb
For each message that your producer creates you should now see your consumer print a message to the screen.
curl -LO http://barkingiguana.com/2009/01/01/writing-rubystomp-clients-with-smqueue.html.orig
curl -LO http://barkingiguana.com/2009/01/01/writing-rubystomp-clients-with-smqueue.html.orig.asc
gpg --verify writing-rubystomp-clients-with-smqueue.html.orig{.asc,}
If you'd like to have a conversation about this post, email craig@barkingiguana.com. I don't bite.