Ruby on Rails: November 2005 Archives

LiveJournal Fun

|

Today I spent more time--by several orders of magnitude--reading LiveJournal entries than I have in the last five years put together. And all this without actually even going to the LiveJournal site. I've been working on a Ruby module to parse Six Apart's update stream service for use in an upcoming site feature, and spent a good chunk of the day watching as entries scrolled across the terminal.

I was a bit worried about how I was going to parse the never ending stream of RSS entries. Most examples of XML parsing assume a (relatively short) document that is parsed into a DOM tree. This clearly isn't an option. Looking through the REXML source files I found a couple attempts at stream parsers. A search on Google found an article demonstrating the use of REXML::Parsers::StreamParser.

The StreamParser example looked good, but it still suffered from the problem that it assumed you would be passing in a string or a file. What I had, however, was a socket. I didn't think it would work, but I just handed the parser my socket and it happily started firing events. With a little more fussing around with code, I was able to set up a simple state machine to decipher the data. Now all I have to do is figure out what to do with it....

The Battle of Rails

|

Today Eric upgraded our development servers at work to the new Rails 0.14.3, also known as Release Candidate 4 for the mythical 1.0 release. As expected, everything promptly broke. All of our sites stopped working. Eric worked some magic and brought the sites back up. He claimed the he didn't do anything more than restart apache, but I have a hard time believing that because I had restarted the server, twice, only moments before.

As I scanned the query logs I noticed that our ActiveRecord caching scheme was suddenly broken. This left me in a bit of a panic. We have developed a clever little caching layer, using the amazing memcached service along with an intra-page cache, that has successfully reduced the number of queries to the database by somewhere between 1/3 to 1/2. Performance would really suffer if we couldn't get the caching to work again.

The caching layer works by decorating ActiveRecord's find, update, destroy, and reload methods. The local cache and memcache are checked for objects before going to the database., while the caches are cleared after an update or destroy and before a reload. Optimistic locking and a reasonable TTL provide a safety net in case anything should go wrong.

I tried going through the Rails source code and change lists to uncover what might have caused the caches to be ignored, but this is a pretty grungy and hard to decipher part of the framework and I made little progress on that front. After some more experimentation, I realized that has_one and belongs_to relationship lookups were no longer calling find but instead were going directly to find_by_sql.

The solution? Another wrapper around find_by_sql that checks for queries of the form "SELECT * FROM table WHERE (table.id = ###) LIMIT 1" and call the cache-enabled find method instead of going to the database. The trick, however, is that if the objects are not in cache then find will call back into find_by_sql and we are then stuck in a loop. A class variable guards against by skipping the sql check in find_by_sql and going directly to the database if it is called as part of the processing of a simple find request.

I fear this caching layer is getting more fragile and more complicated with every revision of Rails. This latest patch is far from polished. It isn't thread safe--that's not a concern for us--and now that I think about it, isn't exception safe either. But at least the caches are working again.

About this Archive

This page is a archive of entries in the Ruby on Rails category from November 2005.

Ruby on Rails: September 2005 is the previous archive.

Ruby on Rails: December 2005 is the next archive.

Find recent content on the main index or look in the archives to find all content.

Pages

Powered by Movable Type 4.1