April 22nd, 2008
If you’ve ever used ActiveResource or for that matter, coded anything that involves interacting with a remote API, you’ve probably had the misfortune of having that API go down or become unresponsive. The experienced old geezers would already have forseen the problem and set a timeout on those API calls. For the rest of us, it’s a good time to get acquainted with the idea of fail-fast and how no response is better than a slow response.
So what happens when the API you’re accessing via ActiveResource or Net::HTTP (or whatever, really, so long as there’s a network socket involved!) becomes unresponsive?
Unfettered outbound remote connections can kill your server
ActiveResource (or Net::HTTP or whatever you’re using) would block while waiting for the API to return. What did we learn about blocking IO in Operating Systems 101? That your process or thread gets stuck waiting for a response that’s what. So now your Mongrel/Thin/Ebb/X web server process basically stuck waiting for a response from an API that might return a response in 30 seconds, or maybe it’ll never return at all. It won’t be long before all your web server processes get blocked and its time to “kill dash nine” (kill -9) some processes and bring out the 500 error page. Yes, your server has been incapacitated and your website is now basically offline.
Timeouts and you
If you’re using Net::HTTP you can easily safeguard yourself against errors like this by setting a timeout on the socket connection. Like so:
def fetch_something_from_some_api(uri)
http = Net::HTTP.new(uri.host, uri.port)
http.read_timeout = timeout
response = http.start { http.request(Net::HTTP::Get.new("#{uri.path}?#{uri.query}")) }
response.is_a?(Net::HTTPSuccess) ? do_something_with(response.body) : nil
rescue Timeout::Error
logger.warn("Timeout accessing #{uri}: #{$!}")
nil
rescue
logger.warn("Error accessing #{uri}: #{$!}")
nil
end
Take note that you really do need to explicitly rescue from the Timeout::Error (or Interrupt) since it’s a child of the Interrupt class and not a StandardError.
Any good client library should also allow you to specify a timeout on the socket connection so read the API documentation.
So what’s this about ActiveResource?
So back to ActiveResource: Michael Koziarski was kind enough to commit my 2 patches (this and this) to ActiveResource so now on edge Rails, you can do this:
class Person < ActiveResource::Base
self.site = 'http://api.people.com:3000/'
self.timeout = 5
end
This sets the timeout to 5 seconds on the underlying Net::HTTP instance that ActiveResource uses. The default timeout (to be exact, the read_timeout) for Net::HTTP is 60 seconds on most Ruby implementations (that includes MRI). That’s far too long if your ActiveResource call is in a public-facing controller!
If you are using ActiveResource anywhere and haven’t safeguarded your application with a timeout, I think it’s a good idea to fix it by using edge Rails or at least applying the patch!
The 2nd ActiveResource patch introduces the ActiveResource::TimeoutError exception that you should rescue from whenever you make an ActiveResource call. When this happens, it’s up to your application to decide what to do (like show a placating we’re sorry message). At least your application is still able to do something!
December 24th, 2007
You may not have noticed this yet, but Rails 2.0 has a new convenient syntax for generating ActiveRecord migrations. Go ahead, run the migration generator with script/generate migration. I’ll wait.
Yup, you can now specify the columns you want to add in your migration by passing attribute/type pairs to the migration generator. Ergo,
script/generate migration AddMoreToAnime episodes:integer licensed:boolean
will generate a migration like so:
class AddMoreToAnime < ActiveRecord::Migration
def self.up
add_column :animes, :episodes, :integer
add_column :animes, :licensed, :boolean
end
def self.down
remove_column :animes, :licensed
remove_column :animes, :episodes
end
end
This ties in pretty nicely with the syntax for the model generator (script/generate model), which also accepts attribute pairs. Tiny change but “it’s all about consistency”.
For the geeks among you, check out the related changeset and ticket.
About the contributor, Pratik Naik
Pratik Naik (WorkingWithRails profile), probably better known as lifofifo or just lifo, is an active Rails contributor and can be found on #rails-contrib and #rubyonrails nearly 24/7. Almost everyone who’s used Rails has used code that lifo has written. Oh, and lifo also won one of the monthly Rails Hackfests.
He also keeps a pretty good blog where he posts mostly on Rails hacking and tips.
December 12th, 2007
I don’t think I need to explain how concatenating your 5 stylesheets and 12 JavaScript files into single files each makes your webpages load faster. Unless you’re using multiple asset hosts (Rails 2 allows for multiple asset hosts), then it becomes tricky to say for sure which method is better, but I digress.
There’re a bunch of really useful plugins that help you bundle your JS and CSS files, most of them offering minifying/packing of JS and stripping of comments and whitespace in CSS as well. I was a big fan (still love it) of Asset Packager, but newer plugins like PackR and Bundle-fu work great too.
With Rails 2.0 though, unless you want the minifying/packing/comment-stripping features, you can do away with installing a packager plugin. Remember your trusty javascript_include_tag and stylesheet_link_tag? They now accept a :cache option:
# :cache => true creates a cached javascript named all.js.
<%= javascript_include_tag :all, :cache => true %>
# This becomes:
# <script type="text/javascript" src="/javascripts/all.js"></script>
# You can name your javascript too, by passing a name instead of true.
<%= javascript_include_tag 'jquery', 'swfobject', 'application', :cache => 'base' %>
# This becomes:
# <script type="text/javascript" src="/javascripts/base.js"></script>
# Same deal for stylesheets...
# :cache => true creates a stylesheet named all.css.
<%= stylesheet_link_tag :all, :cache => true %>
# This becomes:
# <link href="/stylesheets/all.css" media="screen" rel="Stylesheet" type="text/css" />
# You can name your stylesheet like for javascript_include_tag.
<%= stylesheet_link_tag 'yui/reset-fonts-grids', 'application', :cache => 'styles' %>
# This becomes:
# <link href="/stylesheets/styles.css" media="screen" rel="Stylesheet" type="text/css" />
Of course, this only takes place if caching is turned on (ActionController::Base.perform_caching), which is on by default in the production environment and off in the development environment.
For those who want to look at some code, check out the changeset.
About the contributor, DHH
Well, DHH hardly needs any mention. David has_one Wikipedia entry. Nice little touch on this new feature though, I love the convenience.
I promise, like I’d said before, to cover contributions by someone less “mainstream” in the next Rails 2 “feature a day” blog post.
November 20th, 2007
Firefox 3 Beta 1 is out! Check out the pretty sweet list of changes.
If you want to try it, you’ll probably want to run Firefox 3 and Firefox 2 at the same time. Only this time you should remember to rename Firefox 3 so that it doesn’t override your install of Firefox 2.
I’d blogged about some of the changes previously if you care for some screenshots of some of the new features (Mozilla Links covers a good number of new Firefox 3 changes too):
October 26th, 2007
Jeremy Kemper (aka bitsweat) committed a very useful tool into the Rails trunk not too long ago: a request profiler! It’s a human-friendly wrapper script around the ruby-prof library, a nice ruby code profiler, that lets you run multiple requests against a URI in your application and get a detailed code profile report in text and HTML.
Wanna try it out? Update your vendor/rails to at least revision 8016, run rake rails:update to copy the new script/performance/request script into your app’s script directory, install the ruby-prof gem (sudo gem install ruby-prof), then let it loose on your app.
The options are pretty simple, just pass the script the URI you wanna profile. There’re options for specifying how many requests you want to process, and for profiling POST requests, there’s one for
specifying a POST fixture file.
USAGE: script/performance/request uri [options]
-u, --uri [URI] Request URI. Defaults to http://localhost:3000/
-n, --times [0000] How many requests to process. Defaults to 1000.
-b, --benchmark Benchmark instead of profiling
--method [GET] HTTP request method. Defaults to GET.
--fixture [FILE] Path to POST fixture file
--open [CMD] Command to open profile results. Defaults to "open %s &"
-h, --help Show this help
At the end of the run, you get a text and HTML report with the methods called and the time spent in them. If you haven’t seen a code profile before, it looks something like this:
Very nice stuff! It’s extremely convenient to have profiling like this built into Rails itself - personally I’ve not even run any profiling on my Rails code because it seemed like a hassle (though I do run httperf benchmarks and take note the number of requests per second). With code profiling, you can easily see which parts of your code are the bottlenecks and optimize away - it’s a godsend that it’s so easy to do it in Rails!
Anyway, this is all still new stuff I imagine and subject to change (and improvements), but still very exciting for those of us who are hitting performance bottlenecks in our Rails apps (and are not already doing code profiling).