Heroku is a great platform. I like the style of the page, I appreciate the documentation and you can start up for free! One thing that I miss a lot is decent caching. The readonly filesystem eats up a lot of flexibility.
I played around with HTTP caching and Herokus Varnish works really well. The problem is that my app loads a lot of stuff from different 3rd party services like Twitter, so every new visitor will have all the load time on his first visit. Not a surprise that New Relic indicates that request times were ‘Unacceptable’…
I would like to check out the ‘Memcached Basic’ plugin of Heroku, but I did not manage to get into the private beta. So there was no other option than implementing a DB cache.
There is just one requirement that I have. Load stuff from a 3rd party service only if it’s expired. For simplicity, expired means, that the data is older than a predefined interval. In my test environment I like to use a shorter period than in production, so I define the interval in the environment files:
# config/environments/development.rb
CACHE_TIME = 30.seconds
# config/environments/production.rb
CACHE_TIME = 10.hours
A simple key-data pair is enough for my needs, because I always have a unique key for the values I want to cache. I am using Marshal.dump/Marshal.load for serialization, as they play well with anonymous inner classes that YAML can’t deal with. Encoding the data Base64 helps working around some SQLITE issues with serialized data strings:
# app/models/storage.rb
class Storage
The actual caching logic is embeded in my application controller. I provide a simple cache method, that can be called with a block. The block contains the remote call that I want to cache and is only executed if there is no data stored for the given key or the stored data is expired:
# app/controllers/application_controller.rb
def cache(key, &to_cache)
from_db = Storage.first(:conditions => {:key => key})
if from_db.nil? || from_db.updated_at
Finally the data is pushed into an instance varaible, so that I have access to it within my views.
Caching is now as simple as this:
# cache all twitter posts and make them accessible via @tweets
cache(:tweets){Helper::twitter_posts}
This little tweak noteable improved the response time of my app:
This week:
Apdex Score: 0.700.5 (Fair)
Last week:
Apdex Score: 0.060.5 (Unacceptable)
Sugar on rails!
Pingback: Migrating to Rails 3 on Heroku Bamboo | #nofail
Pingback: Using the Redis addon on Heroku | #nofail