Using the Redis addon on Heroku

I am always playing around with new addons offered by Heroku. My latest discovery was the Redis addon that is provided by Redistogo. The addon is probably in private beta (docs are still on beta), but since they put up a link to it on their site, I managed to install it to my personal website that runs in the cloud.

Redis is “an advanced key-value store” and has some features that make it a perfect match for a cache! I use caching extensively on my site and keep on trying out new ways to do it to circumvent Heroku’s readonly filesystem.

Like Memcache, Redis provides the ability to set a time to live (ttl) on a key. This comes in handy, if you have data that expires in a short period of time, like 3rd party data from Twitter etc.

Caching with Redis

Accessing Redis is very simple, since it is a text based protocol. The command reference is straight forward and there is a simple Ruby wrapper available:

require "redis"
redis =
redis.set "foo", "bar"
# => "OK"
redis.get "foo"
# => "bar"

The redis-store gem already provides a Rails 3 compatible Cache Store implementation, but I needed some more configuration points, especially the ttl.

That’s why I wrote my own Rails 3 Redis Cache, also a great way to get used to the way of working with Redis and the Redistogo addon.

Using Rails Redis Cache

There is some configuration needed for Rails to pick up the new cache store. If you want to use different or no caching for test, development and production, you should put the config in your environment files:

# config/environemnts/production.rb
config.action_controller.perform_caching = true
config.cache_store = => ENV['REDISTOGO_URL'])

If there is a Redis server available in all environments, you can put it in your environment file:

# config/environment.rb
ActionController::Base.cache_store = => ENV['REDISTOGO_URL'])

The caching parts are mostly in my controllers:

@tweets = cache("tweets", :expires_in => 30.seconds){ }

The store is using the basic Rails cache store implementation which is broken in the Rails 3.0.0.beta1 version that runs on Heroku, so I added a monkey-patch for that using edge Rails.

Redis on localhost

Installing and running Redis on Mac OS X is really simple:

brew install redis

There is also a commandline client available for direct access:

redis> set "foo" "bar"
redis> get "foo"

It’s key value stores, stupid!

Using blocks in Objective-C

One of my pious intentions for the year 2010 is to start writing some application for the Mac. Apart from the hype about iPhone development, I think that starting out in that area is especially appealing, as it reduces the size of the API one has to learn. Getting to know the iOS libraries is a lot easier than handling the endless amount of Cocoa frameworks.

One thing that I discovered recently is the support of blocks, that has been introduced with OSX 10.6 and iOS 4.0.

the environment matters

Consuming 3rd party data from the web is kind of a pain, especially compared to how easy it is in Ruby. So I was pleased to find Seriously, a framework for async calls and JSON/XML parsing. The Seriously examples made use of blocks:

NSString *url = @"";

[Seriously get:url handler:^(id body, NSHTTPURLResponse *response, NSError *error) {
    if (error) {
        NSLog(@"Error: %@", error);
    else {
        NSLog(@"Look, JSON is parsed into a dictionary!");
        NSLog(@"%@", [body objectForKey:@"profile_background_image_url"]);

Executing this example in my app code raised an error, that I could not easily understand:

"__NSConcreteGlobalBlock", referenced from: ___block_holder_tmp_1.1207 in DZoneController.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

The problem was, that XCode set my execution environment to OSX 10.5 which does not have support for blocks. To fix this, one has to update the MACOSX_DEPLOYMENT_TARGET build variable.

Right Clicking on the XCode project in the “Groups & Files” view will bring up a context menu with “Get Info” (or pressing CMD+I while project is selected). The info pane has a “General” tab that lets you select the “Base SDK for All Configurations”, which I set that to iOS 4.0.
An other option is to search for “MACOSX_DEPLOYMENT_TARGET” in the “Build” tab and changing that value accordingly. Make sure “Show” is set to “All Settings”.

At least some Objective-C sugar!