views:

430

answers:

1

I've been struggling with an issue with ActiveResource for a bit now: when a hostname resolves for an ActiveResource request, but there's no server on the other end to return information, ActiveResource's timeout value doesn't work. The request just hangs.

After reviewing the ActiveResource code, I've realized that this is because the underlying Net:Http object only has one timeout value set: read_timeout. The Net:Http library defines this as "Seconds to wait until reading one block (by one read(2) call)". The Net:Http lib also defines another timeout value, open_timeout, which is defined as "Seconds to wait until connection is opened".

I'm unsure why open_timeout isn't set by default with the timeout value set on an ActiveResource class, but after modifying the ActiveResource::Connection class to include the open_timeout on the http objects, my issue was resolved!

I'm new to rails so I'm unsure of the best way to actually make this modification in my project; I don't want to just change the code in my gem directory. Is there a proper way to make these modifications in a rails project? I've seen that it's possible to load rails classes from the /vendor folder, but do they all have to be there for it to work? I started to make subclasses of the ActiveResource::Base and ActiveResource::Connection classes, but it seemed like maybe there was an easier way to do this, as the function that creates the Net:Http instance is private...any thoughts?

+2  A: 

First of all, this is an issue you should report to Rails' bugtracker: https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/

When I have to hotfix minor things like these, I usually create an initializer file in RAILS_ROOT/config/initializers and reopen the class I intend to fix.

class ActiveResource::Base
  # your fix goes here
end

This is called monkey patching and is somewhat controversial. But I personally consider it quite brutal to introduce a new level into the inheritance hierarchy that has no semantical meaning to my code.

flitzwald
Thanks for the help - that's exactly what i wanted!
Ben
By they way - I'm curious as to why exactly this works? The method I'm overriding in the initializers class is a private method in the ActiveResource::Connection class - and yet this seems to work w/out issue? I can find little information about how files in the initializer folder affect the core rails classes.
Ben
initializer files are in no way special. Their content just gets executed after the environment has been loaded. In Ruby, nothing keeps you from reopening a class and fiddle around with private parts. A methods visibility is a pretty superficial concept in Ruby. You can for example call a private method on an object with obj.send(:private_method, ... )
flitzwald
For posterity's sake: Looks like your ticket (https://rails.lighthouseapp.com/projects/8994/tickets/2947-activeresource-timeout-doesnt-set-open_timeout-on-underlying-nethttp-object) got a patch and was pulled into rails as of v2.3.4: http://github.com/rails/rails/blob/v2.3.4/activeresource/lib/active_resource/connection.rb#L231-232
Jordan Brough