diff --git a/lib/httpx/resolver.rb b/lib/httpx/resolver.rb index f1fef215..9a7b11c3 100644 --- a/lib/httpx/resolver.rb +++ b/lib/httpx/resolver.rb @@ -5,7 +5,7 @@ require "ipaddr" module HTTPX module Resolver - RESOLVE_TIMEOUT = 5 + RESOLVE_TIMEOUT = [2, 3].freeze require "httpx/resolver/resolver" require "httpx/resolver/system" diff --git a/lib/httpx/resolver/system.rb b/lib/httpx/resolver/system.rb index 4611624b..6707b50e 100644 --- a/lib/httpx/resolver/system.rb +++ b/lib/httpx/resolver/system.rb @@ -164,7 +164,8 @@ module HTTPX def async_resolve(connection, hostname, scheme) families = connection.options.ip_families log { "resolver: query for #{hostname}" } - resolve_timeout = @timeouts[connection.origin.host].first + timeouts = @timeouts[connection.origin.host] + resolve_timeout = timeouts.first Thread.start do Thread.current.report_on_exception = false @@ -191,6 +192,8 @@ module HTTPX end rescue StandardError => e if e.is_a?(Timeout::Error) + timeouts.shift + retry unless timeouts.empty? e = ResolveTimeoutError.new(resolve_timeout, e.message) e.set_backtrace(e.backtrace) end diff --git a/sig/resolver.rbs b/sig/resolver.rbs index e353399c..7193184e 100644 --- a/sig/resolver.rbs +++ b/sig/resolver.rbs @@ -2,7 +2,7 @@ module HTTPX type ipaddr = IPAddr | String module Resolver - RESOLVE_TIMEOUT: Integer + RESOLVE_TIMEOUT: Array[Integer] @lookup_mutex: Thread::Mutex diff --git a/test/support/requests/resolvers.rb b/test/support/requests/resolvers.rb index 2dca272a..d74b2a80 100644 --- a/test/support/requests/resolvers.rb +++ b/test/support/requests/resolvers.rb @@ -123,29 +123,22 @@ module Requests end end - # this test mocks an unresponsive DNS server which doesn't return a DNS asnwer back. define_method :"test_resolver_#{resolver_type}_timeout" do - session = HTTPX.plugin(SessionWithPool) - uri = URI(build_uri("/get")) - # absolute URL, just to shorten the impact of resolv.conf search. - uri.host = "#{uri.host}." + start_test_servlet(SlowDNSServer, 12) do |slow_dns_server| + resolver_opts = options.merge(nameserver: [slow_dns_server.nameserver], timeouts: [1, 2]) - resolver_class = Class.new(HTTPX::Resolver::Native) do - def interests - super - :w + HTTPX.plugin(SessionWithPool).wrap do |session| + uri = build_uri("/get") + + before_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :second) + response = session.get(uri, resolver_class: resolver_type, resolver_options: resolver_opts) + after_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :second) + total_time = after_time - before_time + + verify_error_response(response, HTTPX::ResolveTimeoutError) + assert_in_delta 2 + 1, total_time, 12, "request didn't take as expected to retry dns queries (#{total_time} secs)" end - - def dwrite; end end - - before_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :second) - response = session.head(uri, resolver_class: resolver_class, resolver_options: options.merge(timeouts: [1, 2])) - after_time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :second) - total_time = after_time - before_time - - verify_error_response(response, HTTPX::ResolveTimeoutError) - assert_in_delta 2 + 1, total_time, 6, "request didn't take as expected to retry dns queries (#{total_time} secs)" end # this test mocks the case where there's no nameserver set to send the DNS queries to.