Rails, threads and Facebook

Rails is not thread safe framework. That means Rails will process one request at a time. If there is more HTTP client requests they need to wait.

Of course there are some ways to make whole app more responsive. Basically You need to increase Rails instances number and provide some load balancing. mongrel_cluster will do :) but there are other issues.

Even if performance (or rather response time) is not issue, You need to remember that some calls to external APIs could suffer with single Rails app (like those run on webrick). Facebook API has method called FBML.refreshRefUrl to fetch some data from You app and serve it to Facebook’s users directly, from FB’s cache. Calling fbsession.FBML_refreshRefUrl will instantly trigger HTTP GET to Your app (assuming You are refreshing URL from own app, which is probably the case). From my observations Facebook needs this response to finish FBML.refreshRefUrl and get URL properly cached. With single Rails instance, it won’t happen – Webrick will queue HTTP GET from Facebook until RFacebook finish (timeout) call to FBML.refreshRefUrl.

From Yours (as developer) perspective URL won’t be refreshed in fb:ref calls.

There are some other dangers

Opening sockets to third party servers from Rails is potential issue. If there are some troubles making process longer (network congestion) it will freeze particular instance for whole connection setup. And believe me, it could sometimes take long seconds.

Let’s take following example. You have written some web app, which could interact with Facebook, but this is only add-on, main operations are made directly on Your’s application web interface. If application calls directly Facebook API in almost every action (using fbsesison when based on RFacebook) and there is connectivity problem, or performance issues on Facebook, Rails instance will be on hold until RFacebook::FacebookSession#call_method will time out. This could deplete Rails instances pool very fast and make Your application unresponsive to users.

So consider delegating all such tasks (communicating with Facebook API) to separate process and connect to it via DRb, then send request and don’t wait for results. Of course it makes sense only if this API is not crucial to provide Your service. If You are developing Facebook application, accessible only via Facebook web interface (in_canvas) You don’t have worry about that issue – in such setup any connectivity problem means big troubles for Your application.

Interacting with Facebook without user

As a developer of applications based on Facebook Platform I was asking myself how to make changes in user profile not only when user is interacting with application directly.

Users sessions are infinite

First Eureka was to understand, that with Facebook Platform web application, every user session is infinite (does not expire) as long as user has application added to it’s profile. With such session key, Your application can connect to Facebook API and send FBML to user profile. More, it don’t has to be the same user whom session key is used (but, of course, both of users have to have Your application added to theirs profile).

How to connect to API

When connecting from outside of web application, You need to setup session by itself. Of course it does not mean You need to write all code. Probably You need to connect to Your database anyway, so using script/runner is obvious. With runner You can write parts of Rails powered web application, and run it without HTTP request triggering events.

Using RFacebook is also obvious. Only one thing left, how to initialize fbsession? Assuming, that for each user You store in User model filed fbsession for user session key (Facebook session), You can do it with:

   fbsession = RFacebook::FacebookWebSession.new FACEBOOK["key"], FACEBOOK["secret"]
   fbsession.activate_with_previous_session User.find(:first, :conditions => "fbsession IS NOT NULL").fbsession

At this point fbsesison.is_valid? should be returning true, and You can make needed calls to Facebook API.

Understanding what characters are escaped by AR

Working on Facebook application for my customer I’ve been reminded about some basic facts of strings escaping by ActiveRecord. I found a code which could be bug cause in some circumstances – when using find with :conditions => [ "some_field = ?", attr].

This pattern makes attr string passed to database engine safe in context of SQL injection, and is required when dealing with any untrusted data. But You have to remember about % sign, it could be dangerous.

In my customer application there is feature of searching through user database, but it should show only exact matches to last name. There was check to force query to have at least 3 chars, but when You provided % three times, application happily dumped list of all users.

So remember about % sign when results should not return whole dataset.