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 13 def initialize(keepalive_timeout) 14 @pool = {} 15 @factory = Puppet::HTTP::Factory.new 16 @keepalive_timeout = keepalive_timeout 17 end
Public Instance Methods
Returns an Array of entries whose connections are not expired.
@api private
# File lib/puppet/http/pool.rb 142 def active_entries(site) 143 now = Time.now 144 145 entries = @pool[site] || [] 146 entries.select do |entry| 147 if entry.expired?(now) 148 close_connection(site, entry.connection) 149 false 150 else 151 true 152 end 153 end 154 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 92 def borrow(site, verifier) 93 @pool[site] = active_entries(site) 94 index = @pool[site].index do |entry| 95 (verifier.nil? && entry.verifier.nil?) || 96 (!verifier.nil? && verifier.reusable?(entry.verifier)) 97 end 98 entry = index ? @pool[site].delete_at(index) : nil 99 if entry 100 @pool.delete(site) if @pool[site].empty? 101 102 Puppet.debug("Using cached connection for #{site}") 103 entry.connection 104 else 105 http = @factory.create_connection(site) 106 107 start(site, verifier, http) 108 setsockopts(http.instance_variable_get(:@socket)) 109 http 110 end 111 end
# File lib/puppet/http/pool.rb 41 def close 42 @pool.each_pair do |site, entries| 43 entries.each do |entry| 44 close_connection(site, entry.connection) 45 end 46 end 47 @pool.clear 48 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 78 def close_connection(site, http) 79 return false unless http.started? 80 Puppet.debug("Closing connection for #{site}") 81 http.finish 82 true 83 rescue => detail 84 Puppet.log_exception(detail, _("Failed to close connection for %{site}: %{detail}") % { site: site, detail: detail }) 85 nil 86 end
@api private
# File lib/puppet/http/pool.rb 51 def pool 52 @pool 53 end
Release a connection back into the pool.
@api private
# File lib/puppet/http/pool.rb 126 def release(site, verifier, http) 127 expiration = Time.now + @keepalive_timeout 128 entry = Puppet::HTTP::PoolEntry.new(http, verifier, expiration) 129 Puppet.debug("Caching connection for #{site}") 130 131 entries = @pool[site] 132 if entries 133 entries.unshift(entry) 134 else 135 @pool[site] = [entry] 136 end 137 end
Set useful socket option(s) which lack from default settings in Net:HTTP
@api private
# File lib/puppet/http/pool.rb 116 def setsockopts(netio) 117 return unless netio 118 119 socket = netio.io 120 socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true) 121 end
Start a persistent connection
@api private
# File lib/puppet/http/pool.rb 58 def start(site, verifier, http) 59 Puppet.debug("Starting connection for #{site}") 60 if site.use_ssl? 61 verifier.setup_connection(http) 62 begin 63 http.start 64 print_ssl_info(http) if Puppet::Util::Log.sendlevel?(:debug) 65 rescue OpenSSL::SSL::SSLError => error 66 verifier.handle_connection_error(http, error) 67 end 68 else 69 http.start 70 end 71 end
# File lib/puppet/http/pool.rb 19 def with_connection(site, verifier, &block) 20 reuse = true 21 22 http = borrow(site, verifier) 23 begin 24 if http.use_ssl? && http.verify_mode != OpenSSL::SSL::VERIFY_PEER 25 reuse = false 26 end 27 28 yield http 29 rescue => detail 30 reuse = false 31 raise detail 32 ensure 33 if reuse && http.started? 34 release(site, verifier, http) 35 else 36 close_connection(site, http) 37 end 38 end 39 end
Private Instance Methods
# File lib/puppet/http/pool.rb 158 def print_ssl_info(http) 159 buffered_io = http.instance_variable_get(:@socket) 160 return unless buffered_io 161 162 socket = buffered_io.io 163 return unless socket 164 165 cipher = if Puppet::Util::Platform.jruby? 166 socket.cipher 167 else 168 socket.cipher.first 169 end 170 Puppet.debug("Using #{socket.ssl_version} with cipher #{cipher}") 171 end