In this 3rd part we’re going to be concrete but a little bit less technical. Here are 2 big mistakes you have to avoid when trying to setup an IM based application (Sorry for those who wanted more technical info about xmpp4r… maybe in the next one).
The #1 mistake : Trying to run XMPP4r under Rails
I’m not proud to say I did this mistake at first. Perhaps it’s because I was so excited to see xmpp4r in action that my head started making some strange electricity noises, thus short-circuiting my capacity to think rationally. Anyway, please, don’t try to put XMPP4r under your “vendor” directory believing it makes some sense… because it does not. You cannot make a XMPP robot in a Web context. The Web is stateless in nature. User ask for a resource, Apache kicks in and “tunnels” your request to some web framework, a response is returned to the user and then it’s over. (this was over-simplificated… but the main idea is there)
What we need here instead is something that runs on its own, something persistent, something completely independant of user requests on port 80.
So in order to build something out of XMPP4r, you need to create a separate program (in our case it makes sense to call it a listener) that will be running in permanence. But be careful because this could lead to mistake #2.
The #2 mistake : Putting business logic in the listener
I almost thought of doing this mistake but fortunately I didn’t. It would have been awful. Rails (or merb, or whatever) is your friend, you cannot ignore it and code your whole app in plain ruby! You want to get out of your XMPP4r listener as quickly as possible because it is not the “brain” of your application.
Try to make your listener as stupid as possible :
- Receives input (from a callback)
- Sends the data to a standard Rails application (data will be “understood” and “managed” there)
- Sends back to the IM user the response received from the Rails application
So basically the idea is to use the listener for IM interaction only and a Rails application for everything else. Said that way, some self-sufficient cool guys who like to show their attitude could be tempted to take a relax voice and say “Well, duh…”, but it might not be that evident for the rest of us.
So now you know 2 traps to not fall into… how you decide to design your application after that is completely up to you.
I use backgroundrb in rails to do this ~
“I use backgrounrb in rails to do this ~”
Me too – I have a BackgrounDrb worker that is called every 60 minutes that uses Xmpp4r to send an IM and it works very nicely. Like you were talking about, it also separates out the Rails app from the “listener” (or worker with BackgrounDrb).
Frank! I had whiteboarded this structure to code tomorrow when I googled around and found your warning.
Now, what if EVERYTHING I wanted my Rails app to do was unilateral? Users creates account, and rails creates a jabber account for them, too. User changes friend preferences in Rails, and Rails updates roster of friend. Account is deleted, and Rails tells the server to stop saving the equivalent JID.
Would that still smell? The rails and jabber will even be on the same machine. Do I really need confirmations, even?
Anyway, thanks for the head up.
matt
More googling brought your point home, Frank. Here’s a Railsforum post that step by step shows you how to create this backgroundrb listener: http://railsforum.com/viewtopic.php?id=1033/
Matt,
I can’t be of any help with backgroundrb since I had a lot of problems configuring it… so much that I gave up and made a separate listener instead. For some reasons Backgroundrb slowed down our application a lot and made it very unstable. Since our listener doesn’t contain any business logic, the fact that I don’t have access to the Rails application data isn’t a problem at all. What I also like with this setup is the fact that it forces you to see the listener as a separated project. It can have its own repository, its own capistrano deployment recipes… so when you find a bug in the listener, you only have to commit/deploy the listener project while the rails application remains untouched.
EDIT: Oh and I forgot to answer your your first comment, sorry. Sure, if you don’t need to establish a bi-directional conversation with your users, you do not need a “listener”. However your rails app would still have to create a jabber connection (with the whole authentication process) at every requests which would be far from ideal. The best is still to stick with a separated listener (custom or backgroundrb).
Thanks for your comment!