mirror of
https://github.com/HoneyryderChuck/httpx.git
synced 2025-10-07 00:05:02 -04:00
changed timeout so it relies on a loop timeout and a global timeout; both can be disabled
This commit is contained in:
parent
8797eebbf2
commit
65722a3b12
@ -42,8 +42,8 @@ module HTTPX
|
|||||||
branch(**options).request(verb, uri)
|
branch(**options).request(verb, uri)
|
||||||
end
|
end
|
||||||
|
|
||||||
def timeout(klass, **options)
|
def timeout(**args)
|
||||||
branch(timeout: Timeout.by(klass, **options))
|
branch(timeout: args)
|
||||||
end
|
end
|
||||||
|
|
||||||
def headers(headers)
|
def headers(headers)
|
||||||
|
@ -44,7 +44,7 @@ module HTTPX
|
|||||||
:ssl => { alpn_protocols: %w[h2 http/1.1] },
|
:ssl => { alpn_protocols: %w[h2 http/1.1] },
|
||||||
:http2_settings => { settings_enable_push: 0 },
|
:http2_settings => { settings_enable_push: 0 },
|
||||||
:fallback_protocol => "http/1.1",
|
:fallback_protocol => "http/1.1",
|
||||||
:timeout => Timeout.by(:per_operation),
|
:timeout => Timeout.new,
|
||||||
:headers => {},
|
:headers => {},
|
||||||
:max_concurrent_requests => MAX_CONCURRENT_REQUESTS,
|
:max_concurrent_requests => MAX_CONCURRENT_REQUESTS,
|
||||||
:max_retries => MAX_RETRIES,
|
:max_retries => MAX_RETRIES,
|
||||||
@ -65,8 +65,8 @@ module HTTPX
|
|||||||
self.headers.merge(headers)
|
self.headers.merge(headers)
|
||||||
end
|
end
|
||||||
|
|
||||||
def_option(:timeout) do |type, opts|
|
def_option(:timeout) do |opts|
|
||||||
self.timeout = Timeout.by(type, opts)
|
self.timeout = Timeout.new(opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
def_option(:max_concurrent_requests) do |num|
|
def_option(:max_concurrent_requests) do |num|
|
||||||
@ -98,7 +98,7 @@ module HTTPX
|
|||||||
|
|
||||||
merged = h1.merge(h2) do |k, v1, v2|
|
merged = h1.merge(h2) do |k, v1, v2|
|
||||||
case k
|
case k
|
||||||
when :headers, :ssl, :http2_settings
|
when :headers, :ssl, :http2_settings, :timeout
|
||||||
v1.merge(v2)
|
v1.merge(v2)
|
||||||
else
|
else
|
||||||
v2
|
v2
|
||||||
|
@ -1,29 +1,70 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "timeout"
|
||||||
|
|
||||||
module HTTPX
|
module HTTPX
|
||||||
module Timeout
|
class Timeout
|
||||||
class << self
|
LOOP_TIMEOUT = 5
|
||||||
def by(type, **opts)
|
|
||||||
case type
|
def self.new(opts = {})
|
||||||
when :null
|
return opts if opts.is_a?(Timeout)
|
||||||
Null.new(opts)
|
super
|
||||||
when :per_operation
|
end
|
||||||
PerOperation.new(opts)
|
|
||||||
when :global
|
def initialize(loop_timeout: 5, total_timeout: nil)
|
||||||
Global.new(opts)
|
@loop_timeout = loop_timeout
|
||||||
when Null, Global, PerOperation
|
@total_timeout = total_timeout
|
||||||
type.new(opts)
|
reset_counter
|
||||||
when Hash # default way
|
end
|
||||||
PerOperation.new(type)
|
|
||||||
|
def timeout
|
||||||
|
@loop_timeout || @total_timeout
|
||||||
|
ensure
|
||||||
|
log_time
|
||||||
|
end
|
||||||
|
|
||||||
|
def ==(other)
|
||||||
|
if other.is_a?(Timeout)
|
||||||
|
@loop_timeout == other.instance_variable_get(:@loop_timeout) &&
|
||||||
|
@total_timeout == other.instance_variable_get(:@total_timeout)
|
||||||
else
|
else
|
||||||
raise "#{type}: unrecognized timeout option"
|
super
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def merge(other)
|
||||||
|
case other
|
||||||
|
when Hash
|
||||||
|
timeout = Timeout.new(other)
|
||||||
|
merge(timeout)
|
||||||
|
when Timeout
|
||||||
|
loop_timeout = other.instance_variable_get(:@loop_timeout) || @loop_timeout
|
||||||
|
total_timeout = other.instance_variable_get(:@total_timeout) || @total_timeout
|
||||||
|
Timeout.new(loop_timeout: loop_timeout, total_timeout: total_timeout)
|
||||||
|
else
|
||||||
|
raise ArgumentError, "can't merge with #{other.class}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
require "httpx/timeout/null"
|
private
|
||||||
require "httpx/timeout/per_operation"
|
|
||||||
require "httpx/timeout/global"
|
def reset_counter
|
||||||
|
@time_left = @total_timeout
|
||||||
|
end
|
||||||
|
|
||||||
|
def reset_timer
|
||||||
|
@started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
||||||
|
end
|
||||||
|
|
||||||
|
def log_time
|
||||||
|
return unless @time_left
|
||||||
|
return reset_timer unless @started
|
||||||
|
@time_left -= (Process.clock_gettime(Process::CLOCK_MONOTONIC) - @started)
|
||||||
|
if @time_left <= 0
|
||||||
|
raise TimeoutError, "Timed out after #{@total_timeout} seconds"
|
||||||
|
end
|
||||||
|
|
||||||
|
reset_timer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require "timeout"
|
|
||||||
|
|
||||||
module HTTPX::Timeout
|
|
||||||
class Global < PerOperation
|
|
||||||
TOTAL_TIMEOUT = 15
|
|
||||||
|
|
||||||
attr_reader :total_timeout
|
|
||||||
|
|
||||||
def initialize(total_timeout: TOTAL_TIMEOUT)
|
|
||||||
@total_timeout = total_timeout
|
|
||||||
reset_counter
|
|
||||||
@running = false
|
|
||||||
end
|
|
||||||
|
|
||||||
def ==(other)
|
|
||||||
other.is_a?(Global) &&
|
|
||||||
@total_timeout == other.total_timeout
|
|
||||||
end
|
|
||||||
|
|
||||||
def timeout
|
|
||||||
unless @running
|
|
||||||
reset_timer
|
|
||||||
@running = true
|
|
||||||
end
|
|
||||||
log_time
|
|
||||||
@time_left
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def reset_counter
|
|
||||||
@time_left = @total_timeout
|
|
||||||
end
|
|
||||||
|
|
||||||
def reset_timer
|
|
||||||
@started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
||||||
end
|
|
||||||
|
|
||||||
def log_time
|
|
||||||
@time_left -= (Process.clock_gettime(Process::CLOCK_MONOTONIC) - @started)
|
|
||||||
if @time_left <= 0
|
|
||||||
raise HTTPX::TimeoutError, "Timed out after using the allocated #{@total_timeout} seconds"
|
|
||||||
end
|
|
||||||
|
|
||||||
reset_timer
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,16 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module HTTPX::Timeout
|
|
||||||
class Null
|
|
||||||
def initialize(**)
|
|
||||||
end
|
|
||||||
|
|
||||||
def ==(other)
|
|
||||||
other.is_a?(Null)
|
|
||||||
end
|
|
||||||
|
|
||||||
def timeout
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,32 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require "timeout"
|
|
||||||
|
|
||||||
module HTTPX::Timeout
|
|
||||||
class PerOperation < Null
|
|
||||||
OPERATION_TIMEOUT = 5
|
|
||||||
CONNECT_TIMEOUT = 5
|
|
||||||
|
|
||||||
attr_reader :connect_timeout, :operation_timeout
|
|
||||||
|
|
||||||
def initialize(connect: CONNECT_TIMEOUT,
|
|
||||||
operation: OPERATION_TIMEOUT)
|
|
||||||
@connect_timeout = connect
|
|
||||||
@operation_timeout = operation
|
|
||||||
@timeout = @connect_timeout
|
|
||||||
end
|
|
||||||
|
|
||||||
def timeout
|
|
||||||
timeout = @timeout
|
|
||||||
@timeout = @operation_timeout
|
|
||||||
timeout
|
|
||||||
end
|
|
||||||
|
|
||||||
def ==(other)
|
|
||||||
other.is_a?(PerOperation) &&
|
|
||||||
@connect_timeout == other.connect_timeout &&
|
|
||||||
@operation_timeout == other.operation_timeout
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -53,7 +53,6 @@ class OptionsSpec < Minitest::Test
|
|||||||
:ssl => {:foo => "bar"},
|
:ssl => {:foo => "bar"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
assert foo.merge(bar).to_hash == {
|
assert foo.merge(bar).to_hash == {
|
||||||
:io => ENV.key?("HTTPX_DEBUG") ? $stderr : nil,
|
:io => ENV.key?("HTTPX_DEBUG") ? $stderr : nil,
|
||||||
:debug => nil,
|
:debug => nil,
|
||||||
@ -65,7 +64,7 @@ class OptionsSpec < Minitest::Test
|
|||||||
:window_size => 16_384,
|
:window_size => 16_384,
|
||||||
:body_threshold_size => 114_688,
|
:body_threshold_size => 114_688,
|
||||||
:form => {:bar => "bar"},
|
:form => {:bar => "bar"},
|
||||||
:timeout => Timeout::PerOperation.new,
|
:timeout => Timeout.new,
|
||||||
:ssl => {:foo => "bar", :alpn_protocols => %w[h2 http/1.1] },
|
:ssl => {:foo => "bar", :alpn_protocols => %w[h2 http/1.1] },
|
||||||
:http2_settings => { :settings_enable_push => 0 },
|
:http2_settings => { :settings_enable_push => 0 },
|
||||||
:fallback_protocol => "http/1.1",
|
:fallback_protocol => "http/1.1",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user