开发者

Patching classes in Ruby's core lib

开发者 https://www.devze.com 2023-03-31 09:55 出处:网络
I\'m trying to set the timeout for subsequent http calls to a very unreliable API. I tried multiple attempts at using Ruby\'s built-in Timeout.timeout() method but had had no such luck getting it to e

I'm trying to set the timeout for subsequent http calls to a very unreliable API. I tried multiple attempts at using Ruby's built-in Timeout.timeout() method but had had no such luck getting it to extend to sub calls. For example, Timeout.timeout(300) will set the first timeout to 300 but sub calls go back to 60. I added a print of the seconds_delay and here is what I saw:

[16:55:16 miker@laughwhat-lm ~/optisol/src/rails/tools_app/trunk/adhoc/ticket] $ bundle exec ruby buck.rb 
300
nil
warning: peer certificate won't be verified in this SSL session
60
60
nil
warning: peer certificate won't be verified in this SSL session
60

Here is the error I receive with full stack trace:

[16:49:50 miker@laughwhat-lm ~/optisol/src/rails/tools_app/trunk/adhoc/ticket] $ bundle exec ruby buck.rb 
warning: peer certificate won't be verified in this SSL session
warning: peer certificate won't be verified in this SSL session
warning: peer certificate won't be verified in this SSL session
warning: peer certificate won't be verified in this SSL session
warning: peer certificate won't be verified in this SSL session
warning: peer certificate won't be verified in this SSL session
warning: peer certificate won't be verified in this SSL session
/Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/timeout.rb:64:in `rbuf_fill': execution expired (Timeout::Error)
    from /Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/net/protocol.rb:134:in `rbuf_fill'
    from /Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/net/protocol.rb:116:in `readuntil'
    from /Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/net/protocol.rb:126:in `readline'
    from /Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/net/http.rb:2028:in `read_status_line'
    from /Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/net/http.rb:2017:in `read_new'
    from /Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/net/http.rb:1051:in `request_without_fakeweb'
    from /Users/miker/.rvm/gems/ree-1.8.7-2011.03/gems/fakeweb-1.3.0/lib/fake_web/ext/net_http.rb:50:in `request'
    from /Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/net/http.rb:845:in `post'
    from /Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/soap/netHttpClient.rb:93:in `post'
    from /Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/soap/netHttpClient.rb:116:in `start'
    from /Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/net/http.rb:543:in `start'
    from /Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/soap/netHttpClient.rb:115:in `start'
    from /Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/soap/netHttpClient.rb:92:in `post'
    from /Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/soap/streamHandler.rb:170:in `send_post'
    from /Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/soap/streamHandler.rb:109:in `send'
    from /Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/soap/rpc/proxy.rb:170:in `route'
    from /Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/soap/rpc/proxy.rb:141:in `call'
    from /Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/soap/rpc/driver.rb:178:in `call'
    from /Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/soap/rpc/driver.rb:232:in `getByBuyer'
    from buck.rb:9
    from /Users/miker/.rvm/gems/ree-1.8.7-2011.03/gems/yieldmanager-0.8.2/lib/yieldmanager/client.rb:131:in `session'
    from buck.rb:8
    from /Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1.8/timeout.rb:67:in `timeout'
    from /Users/miker/.rvm/rubies/ree-1.8.7-2011.03/lib/ruby/1开发者_高级运维.8/timeout.rb:101:in `timeout'
    from buck.rb:6

So I guess my question would be how can I go about patching the protocol.rb BufferedIO's method to look like this:

class BufferedIO
  private
  def rbuf_fill
    puts "working"
    timeout(300) { # forced 300 second timeout
      @rbuf << @io.sysread(BUFSIZE)
    }
  end
end

Adding that to my ruby file before or after I do my requires/includes does not have an affect (i.e. no "working" is ever printed out). Hope someone has a solution. Thanks!


Of all the various Ruby library's, the clumsiest to work with and ugliest, in my opinion, would have to be net::http. Have you considered switching to something like this:

https://github.com/dbalatero/typhoeus

The requests in typhoeus occur via lib-curl and so aren't bound by Ruby's not-so-reliable when nested or threaded timeout method.

In terms of the rbuf_fill issue, I'm not sure if that will get you there. If I remember correctly, when a timeout exception fires, it always shows the location that the code is currently at in the stack. That location is only incidental. Take the example below I just ran in irb. Notice how it tells you the timeout occured in "sleep"? Where the timeout is reported is just what it happened to be doing at that moment, not where the timeout code is necessarily implemented, nor do you know which timeout it is that is tripping if there are multiple. I'd have to chase down the rbuf_fill to confirm this for you though, and I have to run at the moment...

irb> timeout(2){sleep 5}

Timeout::Error: execution expired from (irb):3:in sleep' from (irb):3:inblock in irb_binding' from (irb):3 from /home/ebelan

0

精彩评论

暂无评论...
验证码 换一张
取 消