Manage your application's gem dependencies with less pain
Latest commit 11e2fea Jul 29, 2016 @homu homu Auto merge of #4812 - NickLaMuro:use_api_timeout_for_net_open_timeout…
…, r=indirect

Add an open_timeout to the fetcher connection

When ruby makes an HTTP connection with the `Net::HTTP` library, by default, it has no timeout to setup that connection.

# excerpts from net/http stdlib
def initialize(address, port = nil)
  @address = address
  @port    = (port || HTTP.default_port)
  @local_host = nil
  @local_port = nil
  @curr_http_version = HTTPVersion
  @keep_alive_timeout = 2
  @last_communicated = nil
  @close_on_empty_response = false
  @socket  = nil
  @started = false
  @open_timeout = nil
  @read_timeout = 60
  # ...


def connect
  if proxy? then
    conn_address = proxy_address
    conn_port    = proxy_port
    conn_address = address
    conn_port    = port

  D "opening connection to #{conn_address}:#{conn_port}..."
  s = Timeout.timeout(@open_timeout, Net::OpenTimeout) {, conn_port, @local_host, @local_port)
  # ...

  if use_ssl?
    # ...
    Timeout.timeout(@open_timeout, Net::OpenTimeout) { s.connect }

It can be set by changing the `open_timeout` variable on the connection object, but beyond that, it will attempt a connection unless an error is returned from the server.  The Net::HTTP::Persistent library included with bundler also maintains this same interface when dealing with threads, and eventually passes that same value down to the Net::HTTP lib.

It is possible to get into a state where bundler is currently attempting to establish a connection indefinitely to rubygems because this timeout is not in place.  Using the `Fetcher.api_timeout`, which is just pulled from the `Bundler.settings[:timeout]` value (defaults to 10 sec), we can also provide an `open_timeout` value and prevent this.  In most cases, and HTTP connection should be established in less than a second (if not, there is probably a bigger problem), and most uses of the Fecther's connection are also wrapped in a Bundler::Retry, so if it fails do to a network hiccup, it will be attempted again.

I was having this happen to me on a pretty consistent basis, and while it is probably more likely my ISP or something fishy with my home network, this seems like a relatively harmless fix.  In the code excerpts above from the STDLIB `net/http`, I would consistently have one or two Threads from the `CompactIndex` stall on the `s.connect`, which was while it was attempting to make an https connection.

Unfortunately, I can't think of a good way to test or reproduce this consistently (and of course, now I can't even reproduce it locally at all), so this PR is more of posing a question of "Do we want to do this, and why or why not?"

Version     Build Status Code Climate Inline docs

Bundler: a gem to bundle gems

Bundler makes sure Ruby applications run the same code on every machine.

It does this by managing the gems that the application depends on. Given a list of gems, it can automatically download and install those gems, as well as any other gems needed by the gems that are listed. Before installing gems, it checks the versions of every gem to make sure that they are compatible, and can all be loaded at the same time. After the gems have been installed, Bundler can help you update some or all of them when new versions become available. Finally, it records the exact versions that have been installed, so that others can install the exact same gems.

Installation and usage

gem install bundler
bundle init
echo 'gem "rspec"' >> Gemfile
bundle install
bundle exec rspec

See for the full documentation.


For help with common problems, see ISSUES.

Other questions

To see what has changed in recent versions of Bundler, see the CHANGELOG.

Feel free to chat with the Bundler core team (and many other users) on IRC in the #bundler channel on Freenode, or via email on the Bundler mailing list.


If you'd like to contribute to Bundler, that's awesome, and we <3 you. There's a guide to contributing to Bundler (both code and general help) over in DEVELOPMENT.

Code of Conduct

Everyone interacting in the Bundler project’s codebases, issue trackers, chat rooms, and mailing lists is expected to follow the Bundler code of conduct.