mirror of
https://github.com/HoneyryderChuck/httpx.git
synced 2025-12-11 00:02:21 -05:00
out with eden connections, keep closed around
connection bookkeeping on the pool changes, where all conections are kept around, even the ones that close during the scope of the requests; new requests may then find them, reset them, an reselect them. this is a major improvement, as objects get more reused, so less gc and object movement. this also changes the way pool terminates, as connections nonw follow a termination protocol, instead of just closing (which they can while scope is open)
This commit is contained in:
parent
b24ed83a8b
commit
ce7eb0b91a
@ -231,6 +231,12 @@ module HTTPX
|
|||||||
@parser.close if @parser
|
@parser.close if @parser
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def terminate
|
||||||
|
@connected_at = nil if @state == :closed
|
||||||
|
|
||||||
|
close
|
||||||
|
end
|
||||||
|
|
||||||
# bypasses the state machine to force closing of connections still connecting.
|
# bypasses the state machine to force closing of connections still connecting.
|
||||||
# **only** used for Happy Eyeballs v2.
|
# **only** used for Happy Eyeballs v2.
|
||||||
def force_reset
|
def force_reset
|
||||||
@ -580,14 +586,14 @@ module HTTPX
|
|||||||
when :inactive
|
when :inactive
|
||||||
return unless @state == :open
|
return unless @state == :open
|
||||||
when :closing
|
when :closing
|
||||||
return unless @state == :open
|
return unless @state == :idle || @state == :open
|
||||||
|
|
||||||
when :closed
|
when :closed
|
||||||
return unless @state == :closing
|
return unless @state == :closing
|
||||||
return unless @write_buffer.empty?
|
return unless @write_buffer.empty?
|
||||||
|
|
||||||
purge_after_closed
|
purge_after_closed
|
||||||
emit(:close)
|
emit(:close) if @pending.empty?
|
||||||
when :already_open
|
when :already_open
|
||||||
nextstate = :open
|
nextstate = :open
|
||||||
# the first check for given io readiness must still use a timeout.
|
# the first check for given io readiness must still use a timeout.
|
||||||
|
|||||||
@ -73,11 +73,11 @@ module HTTPX
|
|||||||
end
|
end
|
||||||
|
|
||||||
def close
|
def close
|
||||||
emit(:close)
|
|
||||||
unless @connection.state == :closed
|
unless @connection.state == :closed
|
||||||
@connection.goaway
|
@connection.goaway
|
||||||
emit(:timeout, @options.timeout[:close_handshake_timeout])
|
emit(:timeout, @options.timeout[:close_handshake_timeout])
|
||||||
end
|
end
|
||||||
|
emit(:close, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def empty?
|
def empty?
|
||||||
|
|||||||
@ -17,8 +17,6 @@ module HTTPX
|
|||||||
@timers = Timers.new
|
@timers = Timers.new
|
||||||
@selector = Selector.new
|
@selector = Selector.new
|
||||||
@connections = []
|
@connections = []
|
||||||
@eden_connections = []
|
|
||||||
@connected_connections = 0
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def empty?
|
def empty?
|
||||||
@ -52,9 +50,8 @@ module HTTPX
|
|||||||
def close(connections = @connections)
|
def close(connections = @connections)
|
||||||
return if connections.empty?
|
return if connections.empty?
|
||||||
|
|
||||||
@eden_connections.clear
|
|
||||||
connections = connections.reject(&:inflight?)
|
connections = connections.reject(&:inflight?)
|
||||||
connections.each(&:close)
|
connections.each(&:terminate)
|
||||||
next_tick until connections.none? { |c| c.state != :idle && @connections.include?(c) }
|
next_tick until connections.none? { |c| c.state != :idle && @connections.include?(c) }
|
||||||
|
|
||||||
# close resolvers
|
# close resolvers
|
||||||
@ -68,16 +65,13 @@ module HTTPX
|
|||||||
resolver.close unless resolver.closed?
|
resolver.close unless resolver.closed?
|
||||||
end
|
end
|
||||||
# for https resolver
|
# for https resolver
|
||||||
resolver_connections.each(&:close)
|
resolver_connections.each(&:terminate)
|
||||||
next_tick until resolver_connections.none? { |c| c.state != :idle && @connections.include?(c) }
|
next_tick until resolver_connections.none? { |c| c.state != :idle && @connections.include?(c) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def init_connection(connection, _options)
|
def init_connection(connection, _options)
|
||||||
resolve_connection(connection) unless connection.family
|
resolve_connection(connection) unless connection.family
|
||||||
connection.timers = @timers
|
connection.timers = @timers
|
||||||
connection.on(:open) do
|
|
||||||
@connected_connections += 1
|
|
||||||
end
|
|
||||||
connection.on(:activate) do
|
connection.on(:activate) do
|
||||||
select_connection(connection)
|
select_connection(connection)
|
||||||
end
|
end
|
||||||
@ -98,6 +92,9 @@ module HTTPX
|
|||||||
connection.on(:close) do
|
connection.on(:close) do
|
||||||
unregister_connection(connection)
|
unregister_connection(connection)
|
||||||
end
|
end
|
||||||
|
connection.on(:terminate) do
|
||||||
|
unregister_connection(connection, true)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def deactivate(connections)
|
def deactivate(connections)
|
||||||
@ -116,16 +113,15 @@ module HTTPX
|
|||||||
connection.match?(uri, options)
|
connection.match?(uri, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
unless conn
|
return unless conn
|
||||||
@eden_connections.delete_if do |connection|
|
|
||||||
is_expired = connection.expired?
|
|
||||||
conn = connection if conn.nil? && !is_expired && connection.match?(uri, options)
|
|
||||||
is_expired
|
|
||||||
end
|
|
||||||
|
|
||||||
if conn
|
case conn.state
|
||||||
|
when :closed
|
||||||
|
conn.idling
|
||||||
|
select_connection(conn)
|
||||||
|
when :closing
|
||||||
|
conn.once(:close) do
|
||||||
conn.idling
|
conn.idling
|
||||||
@connections << conn
|
|
||||||
select_connection(conn)
|
select_connection(conn)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -232,18 +228,12 @@ module HTTPX
|
|||||||
end
|
end
|
||||||
|
|
||||||
def register_connection(connection)
|
def register_connection(connection)
|
||||||
if connection.state == :open
|
|
||||||
# if open, an IO was passed upstream, therefore
|
|
||||||
# consider it connected already.
|
|
||||||
@connected_connections += 1
|
|
||||||
end
|
|
||||||
select_connection(connection)
|
select_connection(connection)
|
||||||
end
|
end
|
||||||
|
|
||||||
def unregister_connection(connection)
|
def unregister_connection(connection, cleanup = !connection.used?)
|
||||||
@connections.delete(connection)
|
@connections.delete(connection) if cleanup
|
||||||
@eden_connections << connection if connection.used? && !@eden_connections.include?(connection)
|
deselect_connection(connection)
|
||||||
@connected_connections -= 1 if deselect_connection(connection)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def select_connection(connection)
|
def select_connection(connection)
|
||||||
|
|||||||
@ -27,7 +27,7 @@ module HTTPX
|
|||||||
use_get: false,
|
use_get: false,
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
def_delegators :@resolver_connection, :state, :connecting?, :to_io, :call, :close
|
def_delegators :@resolver_connection, :state, :connecting?, :to_io, :call, :close, :terminate
|
||||||
|
|
||||||
def initialize(_, options)
|
def initialize(_, options)
|
||||||
super
|
super
|
||||||
|
|||||||
@ -38,6 +38,8 @@ module HTTPX
|
|||||||
|
|
||||||
def close; end
|
def close; end
|
||||||
|
|
||||||
|
alias_method :terminate, :close
|
||||||
|
|
||||||
def closed?
|
def closed?
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|||||||
@ -201,6 +201,7 @@ module HTTPX
|
|||||||
end
|
end
|
||||||
|
|
||||||
connection.merge(existing_connection)
|
connection.merge(existing_connection)
|
||||||
|
existing_connection.terminate
|
||||||
connection
|
connection
|
||||||
rescue UnsupportedSchemeError
|
rescue UnsupportedSchemeError
|
||||||
altsvc["noop"] = true
|
altsvc["noop"] = true
|
||||||
|
|||||||
@ -74,6 +74,8 @@ module HTTPX
|
|||||||
|
|
||||||
def call: () -> void
|
def call: () -> void
|
||||||
|
|
||||||
|
def terminate: () -> void
|
||||||
|
|
||||||
def close: () -> void
|
def close: () -> void
|
||||||
|
|
||||||
def reset: () -> void
|
def reset: () -> void
|
||||||
|
|||||||
@ -6,8 +6,6 @@ module HTTPX
|
|||||||
@timers: Timers
|
@timers: Timers
|
||||||
@selector: Selector
|
@selector: Selector
|
||||||
@connections: Array[Connection]
|
@connections: Array[Connection]
|
||||||
@eden_connections: Array[Connection]
|
|
||||||
@connected_connections: Integer
|
|
||||||
|
|
||||||
def empty?: () -> void
|
def empty?: () -> void
|
||||||
|
|
||||||
@ -37,7 +35,7 @@ module HTTPX
|
|||||||
|
|
||||||
def register_connection: (Connection) -> void
|
def register_connection: (Connection) -> void
|
||||||
|
|
||||||
def unregister_connection: (Connection) -> void
|
def unregister_connection: (Connection, ?bool cleanup) -> void
|
||||||
|
|
||||||
def select_connection: (Selector::selectable) -> void
|
def select_connection: (Selector::selectable) -> void
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,8 @@ module HTTPX
|
|||||||
|
|
||||||
def close: () -> void
|
def close: () -> void
|
||||||
|
|
||||||
|
alias terminate close
|
||||||
|
|
||||||
def closed?: () -> bool
|
def closed?: () -> bool
|
||||||
|
|
||||||
def empty?: () -> bool
|
def empty?: () -> bool
|
||||||
|
|||||||
@ -54,7 +54,8 @@ module Requests
|
|||||||
HTTPX.plugin(SessionWithPool).plugin(ResponseErrorEmitter).wrap do |http|
|
HTTPX.plugin(SessionWithPool).plugin(ResponseErrorEmitter).wrap do |http|
|
||||||
response = http.get(uri)
|
response = http.get(uri)
|
||||||
verify_error_response(response, "done with it")
|
verify_error_response(response, "done with it")
|
||||||
assert http.pool.connections.empty?
|
assert http.pool.connections.size == 1
|
||||||
|
assert http.pool.connections.first.state == :closed
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user