Fork me on GitHub

Libmemcached Store and Passenger

Stemming from the caching issues, I described previously, I decided it was a good opportunity to update our caching implementation. What we had was a hybrid of MemCacheStore for use with fragments and a wrapper around Evan Weaver’s memcached gem for a few other processes. This was a bit quirky, not to mention fragile. Multiple implementations, multiple configurations. Smelly code, for sure.

I’ve worked with other caching frameworks before and while i was loathe to introduce any new complexity, it seemed that the best approach was to unify the two implementations as much as possible. That meant staying away from cache_fu, cache-money, interlock, etc. There’s been a dearth of caching libraries popping up over the past year or so. I suspect that’s because many people are using Rails internal caching. That led me to look at cache_stores, and libmemcached_store from 37 Signals. It was a breeze to implement as a drop-in replacement for MemCacheStore.

The only catch was, we’re using passenger. I wanted to make sure that LibmemcachedStore played nice with passenger’s spawning process. Here’s how to do it:

It’d be nice if all cache stores implemented a reset or disconnect method, in the meantime, we have hacks like this.

Adventures in Rails Caching

For the past week or so, I’ve been racking my brain trying to resolve an issue with memcached. Basically, several times a day our data was disappearing. We had plenty of memory to use so that definitely wasn’t a factor. Yet daily, we experienced data loss. This led me on a meandering path of troubleshooting, was it the ruby driver? was it the older version of memcached we were running? Could it have been the controller action that called Rails.cache.clear? (BTW, don’t do this)

I noticed a pattern, this always happened in the morning, typically beginning around 9:15. With that, I scanned crontab to see what jobs might’ve been running around that time. I came to find a call to a rake task in our codebase: cache:fragment:delete:

So, whenever this rake task is run, it deletes the fragments. Right? Wrong.

In this case, we didn’t define a cache store for ActionController, but we did define a cache_store for ActiveSupport. So where were the fragments? In memcached. And that innocuous call to delete the fragments was flushing memcached! It turns out that when you don’t define a separate cache store for ActionController, it uses whatever cache store is configured for ActiveSupport. A quick look at the rails initializer code confirms this:

This is how it should work. Why assume a separate cache store when you’ve configured one elsewhere in your app? This makes total sense, but it was quite the gotcha when I realized what was happening. Why was the cache being cleared, you ask? Well, the key generation scheme changed within rails somewhere along the way so the specific call to delete the fragment was no longer working. All I had to do was figure out what the proper key should be, expire that fragment specifically, and all was right in the world.

Introducing jsonwhois

I’ve been at Railconf 2010 all week and it’s been awesome. I’m heading home with a laundry list a mile long of different technologies to experiment with and learn about. I wanted a small side project to hack on while in between sessions and came up with jsonwhois. The idea behind it is really simple, serve up whois via JSON. The implementation was equally simple, using Simone Carletti’s whois gem which handled all the hard stuff, I merely had to wrap it in a sinatra framework.

There was one tricky aspect that I had to overcome, the whois gem utilizes the ruby Struct object for some of it’s underlying data. Structs are simple and lightweight, but for some reason, the json gem wasn’t handling them properly. What’s more, I didn’t really like how the json gem serialized them anyway. The workaround: Struct#hash. Struct#hash returns a struct’s contents as a hash. It’s exactly what I wanted as I felt it was a cleaner representation for JSON anyway. All that was required then was to extend Struct and implement to_json using the hash:

One other interesting tidbit was that I wanted to actually read the JSON through the browser. I decided it was best to look at the incoming headers and use that to determine the appropriate response type to send back. If you accept application/json, that’s what i give you, otherwise it comes back as test/plain. If there’s a better way to do this, please let me know, this seemed logical though:

The code is up on github if anyone want to look under the covers.