class Puppet::HTTP::Pool
A pool for persistent `Net::HTTP` connections. Connections are stored in the pool indexed by their {Site}. Connections are borrowed from the pool, yielded to the caller, and released back into the pool. If a connection is expired, it will be closed either when a connection to that site is requested, or when the pool is closed. The pool can store multiple connections to the same site, and will be reused in MRU order.
@api private
Attributes
Public Class Methods
# File lib/puppet/http/pool.rb 14 def initialize(keepalive_timeout) 15 @pool = {} 16 @factory = Puppet::HTTP::Factory.new 17 @keepalive_timeout = keepalive_timeout 18 end
Public Instance Methods
Returns an Array of entries whose connections are not expired.
@api private
# File lib/puppet/http/pool.rb 143 def active_entries(site) 144 now = Time.now 145 146 entries = @pool[site] || [] 147 entries.select do |entry| 148 if entry.expired?(now) 149 close_connection(site, entry.connection) 150 false 151 else 152 true 153 end 154 end 155 end
Borrow and take ownership of a persistent connection. If a new connection is created, it will be started prior to being returned.
@api private
# File lib/puppet/http/pool.rb 93 def borrow(site, verifier) 94 @pool[site] = active_entries(site) 95 index = @pool[site].index do |entry| 96 (verifier.nil? && entry.verifier.nil?) || 97 (!verifier.nil? && verifier.reusable?(entry.verifier)) 98 end 99 entry = index ? @pool[site].delete_at(index) : nil 100 if entry 101 @pool.delete(site) if @pool[site].empty? 102 103 Puppet.debug("Using cached connection for #{site}") 104 entry.connection 105 else 106 http = @factory.create_connection(site) 107 108 start(site, verifier, http) 109 setsockopts(http.instance_variable_get(:@socket)) 110 http 111 end 112 end
# File lib/puppet/http/pool.rb 42 def close 43 @pool.each_pair do |site, entries| 44 entries.each do |entry| 45 close_connection(site, entry.connection) 46 end 47 end 48 @pool.clear 49 end
Safely close a persistent connection. Don't try to close a connection that's already closed.
@api private
# File lib/puppet/http/pool.rb 79 def close_connection(site, http) 80 return false unless http.started? 81 Puppet.debug("Closing connection for #{site}") 82 http.finish 83 true 84 rescue => detail 85 Puppet.log_exception(detail, _("Failed to close connection for %{site}: %{detail}") % { site: site, detail: detail }) 86 nil 87 end
@api private
# File lib/puppet/http/pool.rb 52 def pool 53 @pool 54 end
Release a connection back into the pool.
@api private
# File lib/puppet/http/pool.rb 127 def release(site, verifier, http) 128 expiration = Time.now + @keepalive_timeout 129 entry = Puppet::HTTP::PoolEntry.new(http, verifier, expiration) 130 Puppet.debug("Caching connection for #{site}") 131 132 entries = @pool[site] 133 if entries 134 entries.unshift(entry) 135 else 136 @pool[site] = [entry] 137 end 138 end
Set useful socket option(s) which lack from default settings in Net:HTTP
@api private
# File lib/puppet/http/pool.rb 117 def setsockopts(netio) 118 return unless netio 119 120 socket = netio.io 121 socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true) 122 end
Start a persistent connection
@api private
# File lib/puppet/http/pool.rb 59 def start(site, verifier, http) 60 Puppet.debug("Starting connection for #{site}") 61 if site.use_ssl? 62 verifier.setup_connection(http) 63 begin 64 http.start 65 print_ssl_info(http) if Puppet::Util::Log.sendlevel?(:debug) 66 rescue OpenSSL::SSL::SSLError => error 67 verifier.handle_connection_error(http, error) 68 end 69 else 70 http.start 71 end 72 end
# File lib/puppet/http/pool.rb 20 def with_connection(site, verifier, &block) 21 reuse = true 22 23 http = borrow(site, verifier) 24 begin 25 if http.use_ssl? && http.verify_mode != OpenSSL::SSL::VERIFY_PEER 26 reuse = false 27 end 28 29 yield http 30 rescue => detail 31 reuse = false 32 raise detail 33 ensure 34 if reuse && http.started? 35 release(site, verifier, http) 36 else 37 close_connection(site, http) 38 end 39 end 40 end
Private Instance Methods
# File lib/puppet/http/pool.rb 159 def print_ssl_info(http) 160 buffered_io = http.instance_variable_get(:@socket) 161 return unless buffered_io 162 163 socket = buffered_io.io 164 return unless socket 165 166 cipher = if Puppet::Util::Platform.jruby? 167 socket.cipher 168 else 169 socket.cipher.first 170 end 171 Puppet.debug("Using #{socket.ssl_version} with cipher #{cipher}") 172 end