• Living on the edge (of Rails) #18

    This week’s report covers changes from 21 Apr 2008 to 27 Apr 2008 (the day the corresponding Rails Envy podcast was recorded).

    Not much interesting to report this week - there were mostly a bunch of bugfixes and Ruby 1.8.7-compatibility commits.

    Introduce ActiveResource::Base.timeout and rescuing from Timeout::Error in ActiveResource::Connection

    These are 2 changes that I'd talked about earlier this week so I won't repeat myself - take a read through ActiveResource timeouts and why it matters.

    Smart integer datatype for the MySQL adapter in migrations

    The MySQL adapter in Rails now maps the integer column type in your migrations to either smallint, int, or bigint depending on the :limit option.

    This means that a migration like this:

    def self.up
      create_table :searches do |t|
        t.integer :foo, :limit => 2
      end

    will create your foo column as a smallint(2) MySQL datatype (instead of int(2) before). (More information MySQL numeric datatypes.)

    Credit goes to DHH for this patch.

    Related changeset: http://github.com/rails/rails/commit/a37546517dad9f6d9a7de6e1dba4d960909d71e8

    As always, let me know of any suggestions or how I can improve the Living on the Edge (of Rails) series.

  • New in Rails: ActiveResource timeouts and why it matters

    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.

    im in ur serverz making thingz better


    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!

  • Living on the edge (of Rails) #17

    Not much going on this week on edge Rails. It does seem however that we do have a new Rails core member, Joshua Peek. Also, the new Rails' bug tracker hosted on Lighthouse is ready for use, so be sure to submit your patches and bug reports there.

    This week’s report covers changes from 14 Apr 2008 to 20 Apr 2008 (the day the corresponding Rails Envy podcast was recorded).

    Conditional caches_page

    The caches_page now takes an :if option for specifying when a page can actually be cached via a Proc. You can now do this, for example:

    caches_page :index, :if => Proc.new { |c| !c.request.format.json? }

    That will only cache your index page if the requested format is not JSON.

    Credit goes to Paul Horsfall for this enhancement.

    Related changeset: http://github.com/rails/rails/commit/14a40804a29a57ad05ca6bffbe1e5334089593a9

    New ActionView::TestCase for testing view helpers

    Remember how you can now use specialized TestCase classes for testing controllers and ActionMailer classes? Now you can do the same with your Rails view helpers with the new ActionView::TestCase class.

    Here's a quick example:

    module PeopleHelper
      def title(text)
        content_tag(:h1, text)
      end
    
      def homepage_path
        people_path
      end
    end
    
    class PeopleHelperTest < ActionView::TestCase
    def setup
      ActionController::Routing::Routes.draw do |map|
        map.people 'people', :controller => 'people', :action => 'index'
        map.connect ':controller/:action/:id'
      end
    end
    
    def test_title
      assert_equal "<h1>Ruby on Rails</h1>", title("Ruby on Rails")
    end
    
    def test_homepage_path
      assert_equal "/people", homepage_path
    end

    Credit goes to Josh Peek for this sweet little enhancement.

    ActiveSupport::Cache's mem_cache_store accepts options

    Even though Memcache-client was added to ActiveSupport recently, it didn't allow you to specify any configuration options beyond just the IP of the memcached server. Now you can pass along more configuration options like so:

    config.action_controller.fragment_cache_store = :mem_cache_store, 'localhost', { :compression => true, :debug => true, :namespace => 'foo' }

    This patch is courtesy of Jonathan Weiss.

    Related changeset: http://github.com/rails/rails/commit/9e1d506a8cfedef2fdd605e4cbf4bf53651ad214

    As always, let me know of any suggestions or how I can improve the Living on the Edge (of Rails) series.

  • Command history meme

    See this.

    history | awk '{a[$2]++}END{for(i in a){print a[i] " " i}}' | sort -rn | head

    4605 cd
    3576 svn
    2141 ls
    1701 ruby
    1308 cap2
    1066 ss
    978 rake
    867 sshb
    688 rm
    635 mate

    cap2 is just my alias for Capistrano 2 (I use both 1.x and 2.x, since I'm lazy to upgrade some old Rails applications, ss is my alias for script/server. sshb is a shortcut for ssh with a certain port number for SSH daemons (i.e. -p 22) that we use in Bezurk (you know, security through obscurity).

  • Living on the edge (of Rails) #16 - Github edition

    A slight change this week since Rails has moved to Git - all changesets are now referenced to Github.

    This week’s report covers changes from 7 Apr 2008 to 13 Apr 2008 (the day the corresponding Rails Envy podcast was recorded).

    A helpers proxy method for accessing helper methods from outside of views

    A helpers method has been introduced to ActionController - you can now access your helpers like so:

    ApplicationController.helpers.simple_format(text)

    Credit goes to 19 year old Josh Peek, one of the more prolific Rails contributors (and most likely to join Pratik in Rails Core imo).

    Related changeset: http://github.com/rails/rails/commit/917423d664038d6791738a73ad1446437dbb71df

    json_escape for escaping HTML entities in JSON strings

    A json_escape (aliased as j, similar to how html_escape is aliased as h) has been introduced by Rick Olson for escaping HTML entities in JSON strings. This is useful if you find yourself emitting JSON strings in HTML pages (e.g. for documenting a JSON API):

    json_escape("is a > 0 & a < 10?")
    # => is a \u003E 0 \u0026 a \u003C 10?

    Of course, since json_escape is aliased as j, you can do this in your ERB templates:

    <%=j @person.to_json %>

    Related changeset: http://github.com/rails/rails/commit/0ff7a2d89fc95dcb0a32ed92aab7156b0778a7ea

    Automatically parse posted JSON content for Mime::JSON requests

    Rails will now accept POSTed JSON content! For example, you can now send a POST to "/posts" of your Post resource like this:

    POST /posts
    {"post": {"title": "Breaking News"}}

    And your create action will automatically parse the POSTed JSON into the request params so that this code below just works:

    def create
      @post = Post.create params[:post]
    end

    Credit goes to Rick Olson.

    Related changeset: http://github.com/rails/rails/commit/4d594cffcfc93b37fad4e423ec8593299e50133c

    schema_migrations table replaces the schema_info table, allowing for interleaved migrations

    A new schema_migrations table for storing which migrations have been run has been introduced, and this replaces the existing schema_info table (which simply keeps track of the last applied schema version). This change makes it possible to add migrations (for example, after you've merged from someone's branch) - when you migrate your database via rake db:migrate, those never-applied "interleaved" migrations will be run. Similarly, when migrating down schema versions, never-applied "interleaved" will be skipped.

    See http://dev.rubyonrails.org/ticket/11493 for more information.

    This useful patch is the brainchild of Jordi Bunster (WWR profile). I'm sure many Rails developers who branch extensively will thank Jordi for this excellent patch!

    Related changeset: http://github.com/rails/rails/commit/8a5a9dcbf64843f064b6e8a0b9c6eea8f0b8536e

    gems:unpack:dependencies Rake task

    Remember how you can now run the gems:unpack Rake task to unpack a gem into your vendor/gems/ directory (this was mentioned in an earlier Living on the Edge)?

    David Dollar (Github profile) has firmed up that patch quite a bit by adding the gems:unpack:dependencies Rake task that unpacks the dependencies of the gems as well. So running:

    gems:unpack:dependencies GEM=activecouch

    would unpack the full Rubygem dependency tree of gems that the activecouch gem depends upon.

    Related changeset: http://github.com/rails/rails/commit/4364c361b599f99bc2345ce4eb2d145b07ed8a0f

    As always, let me know of any suggestions or how I can improve the Living on the Edge (of Rails) series! Now go out there and start forking Rails!

subscribe via RSS