Distributed programming with Jabber and EventMachine
Jabber and its underlying protocol XMPP are typically associated with instant messaging applications, although the breadth and flexibility of the technology allows for implementations that can span further from traditional online chatting.
ejabberd is a fault tolerant and clusterable Jabber/XMPP server written in Erlang and presents an interesting option as a simple, lightweight and scalable message transport for distributed applications.
EventMachine is a simple and fast library for lightweight concurrency in Ruby. Its use mainly involves, but is not limited to, spawning lightweight processes whose execution can be programatically scheduled, easy and fast socket abstractions and an implementation of the Deferrable pattern as introduced by the Twisted event-driven Python networking engine.
When a Ruby class includes the EventMachine::Deferrable module, it is provided with the ability to accept arbitrary callbacks and errbacks that will get executed when its deferred status changes, in particular when it is set to either :succeeded or :failed. Let’s look at a deferrable Worker class which performs a potentially long running operation.
class Worker
include EM::Deferrable
def heavy_lifting
30.times do |i|
puts "Lifted #{i}"
sleep 0.1
end
set_deferred_status :succeeded
end
end
Inside an EventMachine loop, we can add callbacks to a Worker instance and dispatch the expensive operation to a separate thread, or an evented process. The program’s execution will continue, with any callbacks attached to Worker executed once its deferred status is set.
EM.run do
worker = Worker.new
worker.callback {p "done!"}
Thread.new {worker.heavy_lifting; EM.stop}
puts "resuming remaining program operations"
end
Now, let’s look at combining Worker with Jabber to trigger long running jobs. For Jabber server duties, I am using ejabberd on an old laptop running Debian, but there’s no reason why a mass online Jabber service like Google Talk could not be used for playing around with the example. Also, I’m using the xmpp4r-simple Ruby library, which is a wrapper around xmpp4r.
jabber = Jabber::Simple.new("bot@thrash", "password")
at_exit{jabber.status(:away, "jabot down")}
EM.run do
EM::PeriodicTimer.new(1) do
jabber.received_messages do |message|
case message.body
when "exit" : EM.stop
when "lift" :
EM.spawn do
worker = Worker.new
worker.callback {jabber.deliver(message.from, "Done lifting")}
worker.heavy_lifting
end.notify
jabber.deliver(message.from, "Scheduled heavy job...")
else jabber.deliver(message.from, "Dunno how to #{message.body}")
end
end
end
end
Inside an EventMachine loop, we check for new messages every second. The program understands two commands, exit and lift. The first quits the EventMachine loop and ultimately terminates the program’s execution. When lift is received, we instantiate a new Worker inside a spawned process and add a callback so that the Worker will notify the command issuer when the job has completed. Worth noting is the use of notify to schedule the spawned process. notify returns immediately making work dispatch non-blocking - upon issuing a lift command twice, a “Scheduled heavy job…” message will be sent to the job issuer twice before the first job completes.
I use Adium to send commands to the program - an interesting way of remote controlling or interacting with applications. Of course, the real interest lies in using the setup under discussion for inter-app communication. With multicast options, presence discovery, node status updates and more, there is lot to explore in terms of distributed application development, if simple and lightweight are two keywords to be found on the highest ranks of your list.

May 4th, 2008 at 9:13 pm
[...] tagged onlineOwn a Wordpress blog? Make monetization easier with the WP Affiliate Pro plugin. Distributed programming with Jabber and EventMachi… saved by 1 others PEACendwarWORLDpeace bookmarked on 05/04/08 | [...]
May 5th, 2008 at 3:12 pm
nutrun » Blog Archive » Distributed programming with Jabber and EventMachine…
nutrun » Blog Archive » Distributed programming with Jabber and EventMachine…
May 5th, 2008 at 3:22 pm
Great thinking.
I’ve spent some time looking at a similar solution using ActiveMQ/STOMP and the Ruby STOMP library. I also have working a similar solution using XMPP from within a Rails-based suite of applications using BackgroundRB. My thought is that Rails could serve as a service container mechanism with XMPP as an Enterprise Service Bus mechanism. However, I never really got around to the idea of a registry and discovery model. But, after reading your post I can see how the Presence capability could work.
We’d done our work using OpenFire, an Open Source Jabber server written in Java. Not the lightest weight server for sure, but very easy to use and has a sweet plugin architecture.
May 5th, 2008 at 5:47 pm
The code here is very bothersome to read.
May 5th, 2008 at 5:56 pm
Ha. Strangely, I just ended up on another one of your blog posts: http://nutrun.com/weblog/jms-with-jruby-and-activemq/
So, it looks like you and I are thinking about many of the same things. Curious, have you added OSGi to your list?
Something I starting to look at is the potential for packaging up Ruby “services” within JRuby/OSGi for deployment to servers like ServiceMix, OpenESB or just GlassFish and Tomcat
May 6th, 2008 at 12:30 am
[...] Distributed programming with Jabber and EventMachine (tags: ruby jabber programming) [...]
May 6th, 2008 at 12:46 am
[...] nutrun » Blog Archive » Distributed programming with Jabber and EventMachine (tags: distributed erlang jabber performance programming ruby xmpp) [...]
May 6th, 2008 at 1:25 am
I do hope XMPP doesn’t become the event system of distributed storage. I wrote an instant messenger on it once and the protocol is just plain bad. Lots of elements called ‘a’ and ‘x’ all with different namespaces.
It’s about time we had a new IM protocol, maybe based around ATOM.
May 6th, 2008 at 6:34 am
[...] nutrun » Blog Archive » Distributed programming with Jabber and EventMachine Distributed programming with Jabber and EventMachine (tags: development distributed events jabber ruby xmpp) [...]
May 6th, 2008 at 9:19 am
Distributed programming with Jabber and EventMachine…
[...]Jabber and its underlying protocol XMPP are typically associated with instant messaging applications, although the breadth and flexibility of the technology allows for implementations that can span further from traditional online chatting.[...]…
May 6th, 2008 at 9:29 am
nutrun » Blog Archive » Distributed programming with Jabber and EventMachine…
[...][...]…
May 6th, 2008 at 7:45 pm
[...] nutrun » Blog Archive » Distributed programming with Jabber and EventMachine [...]
May 7th, 2008 at 4:32 am
[...] nutrun » Blog Archive » Distributed programming with Jabber and EventMachine (tags: jabber eventmachine delayed processing method rails) [...]
May 9th, 2008 at 4:15 pm
[...] Distributed programming with Jabber and EventMachine [...]
May 22nd, 2008 at 2:18 am
[...] also an article about using EventMachine with Jabber to create a Jabber Bot that’s worth [...]
May 23rd, 2008 at 4:19 pm
I like the idea, and I think this could be a good fit for the Jabber PubSub spec (http://www.xmpp.org/extensions/xep-0060.html). This way multiple application could “subscribe” to a node where other applications can pass events, and those applications can process those events however they need to. This event model could be easily distributed, and if you used ejabberd as your jabber server, you could have a pretty powerful and fault tolerant way to perform distributed programming tasks. Very very interesting.
July 2nd, 2008 at 5:41 pm
I haven’t used the Jabber protocol as a message queue before like this, but my only concern is does it allow some sort of way to ensure that each message has guaranteed one-time delivery? If I sent out a message to the “cloud” I would want to make sure every message is either processed by a worker or held in the queue until a worker is available. My concern is that if workers were backed up, or (worst case) completely down, I would want to ensure no messages were lost.