views:

207

answers:

3

I'm trying to contact a REST API using ActiveResource on Rails 2.3.2.

I'm attempting to use the timeout functionality so that if the resource I'm contacting is down I can fail quickly - I'm doing this with the following:

class WorkspaceResource < ActiveResource::Base
  self.timeout = 5
  self.site = "http://mysite.com/restAPI"
end

However, when I try to contact the service when I know it isn't available, the class only times out after the default 60 seconds. I can see from the error stack that the timeout error does indeed come from an ActiveResource class in my gem folder that has the proper functions to allow timeout settings, but my set timeout never seems to work.

Any thoughts?

A: 

The problem

If you're running on Ruby 1.8.x then the problem is its lack of real system threads.

As you can read first hereand then here, there are systemic problems with timeouts in Ruby. An interesting discussion but for you in particular some comments suggest that the timeout is effectively ignored and defaults to 60 seconds - exactly what you are seeing.


Solutions ...

I have a similar issue with our own product when trying to send emails - if the email server is down the thread blocks. For me the solution was to spin the request off on a separate thread and therefore my main request-processing thread doesn't block.

There are non-blocking libraries out there for Ruby but perhaps you could take a look first at this System Timeout Gem.

An option open to anyone using Rails behind a proxy like nginx would be to set the upstream timeout to a lower number - that way you'll get notified if the server is taking too long. I'd only do this if I were really stuck for a solution.

Last but not least, it's possible that running Rails 2.3.2 on top of Ruby 1.9.1 will fix the issue.

Chris McCauley
Thanks for the response - I am using 2.3.2, and I don't think threading is the issue - see my comment below
Ben
A: 

So apparently the issue is not that timeout is not functioning. I can run a server locally, make it not return a response within the timeout limit, and see that timeout works.

The issue is in fact that if the server does not accept the connection, timeout does not function as I expected it to - it doesn't function at all. It appears as though timeout only works when the server accepts the connection but takes too long to respond.

To me, this seems like an issue - shouldn't timeout also work when the server I'm contacting is down? If not, there should be another mechanism to stop a bunch of requests from hanging...anyone know of a quick way to do this?

Ben
In the case that the server isn't running, you shouldn't even get as far as the timeout not working. If it's hanging trying to connect to a server that isn't running then you have some other issue. Have you actually seen this case?
Chris McCauley
I have seen this, although I can't quite figure out what makes it happen. I don't see it when I attempt to connect to a non-existent hostname. But, when i point to an IP in my network that should be running a server but is not, the process just hangs for 60 seconds (maybe even longer). So, for ex:class WorkspaceResource < ActiveResource::Base self.timeout = 5 self.site = "http://192.168.11.3:80/api/"endwill hang. I imagine this is exactly the case I'll be presented w/if the API i'm trying to reach is down?
Ben
A: 

Actually found out the answer myself, discussing in another thread here:

http://stackoverflow.com/questions/1176528/overriding-modifying-rails-class-activeresource

Ben
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