diff --git a/Gemfile.lock b/Gemfile.lock index 97e30d8..a05a20a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - veryfi (4.0.0) + veryfi (4.0.1) base64 (~> 0.1) faraday (>= 2.14.1, < 3.0) openssl (>= 2.2, < 4.1) @@ -23,15 +23,15 @@ GEM rexml diff-lcs (1.6.2) docile (1.4.1) - faraday (2.14.2) + faraday (2.14.3) faraday-net_http (>= 2.0, < 3.5) json logger - faraday-net_http (3.4.3) + faraday-net_http (3.4.4) net-http (~> 0.5) hashdiff (1.2.1) io-console (0.8.2) - json (2.19.5) + json (2.20.0) language_server-protocol (3.17.0.5) lint_roller (1.1.0) logger (1.7.0) diff --git a/lib/veryfi/client.rb b/lib/veryfi/client.rb index a53cb81..d5aeeb8 100644 --- a/lib/veryfi/client.rb +++ b/lib/veryfi/client.rb @@ -50,7 +50,7 @@ def initialize( api_key:, base_url: "https://api.veryfi.com/api/", api_version: "v8", - timeout: 20, + timeout: 30, faraday: nil ) @request = Veryfi::Request.new( diff --git a/lib/veryfi/configuration.rb b/lib/veryfi/configuration.rb index fe60074..eb26493 100644 --- a/lib/veryfi/configuration.rb +++ b/lib/veryfi/configuration.rb @@ -15,7 +15,7 @@ class Configuration def initialize @base_url = "https://api.veryfi.com/api/" @api_version = "v8" - @timeout = 20 + @timeout = 30 end # @return [Hash] the configuration as a keyword-arg-ready Hash. Keys diff --git a/lib/veryfi/request.rb b/lib/veryfi/request.rb index 9b0efed..f3a7790 100644 --- a/lib/veryfi/request.rb +++ b/lib/veryfi/request.rb @@ -64,8 +64,7 @@ def make_request(http_verb, path, params = {}) url = [api_url, path].join body = generate_body(http_verb, params) headers = generate_headers(params) - - response = conn.public_send(http_verb, url, body, headers) + response = attempt_request(http_verb, url, body, headers) json_response = process_response(response) if response.success? @@ -75,6 +74,15 @@ def make_request(http_verb, path, params = {}) end end + def attempt_request(http_verb, url, body, headers) + conn.public_send(http_verb, url, body, headers) + rescue Faraday::TimeoutError => e + raise unless e.message.include?("closed") + + @_conn = nil + conn.public_send(http_verb, url, body, headers) + end + def conn @_conn ||= Faraday.new do |conn| conn.options.timeout = timeout diff --git a/lib/veryfi/version.rb b/lib/veryfi/version.rb index 162f275..0370e81 100644 --- a/lib/veryfi/version.rb +++ b/lib/veryfi/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module Veryfi - VERSION = "4.0.0" + VERSION = "4.0.1" end diff --git a/spec/veryfi/request_spec.rb b/spec/veryfi/request_spec.rb index 77345e2..3337af3 100644 --- a/spec/veryfi/request_spec.rb +++ b/spec/veryfi/request_spec.rb @@ -94,6 +94,29 @@ end end + describe "stale connection recovery" do + let(:request) do + described_class.new("cid", nil, "u", "k", "https://api.veryfi.com/api/", "v8", 30) + end + + let(:endpoint) { "https://api.veryfi.com/api/v8/partner/documents/" } + + it "retries once after a closed-socket ReadTimeout" do + stub_request(:get, endpoint) + .to_raise(Faraday::TimeoutError.new("Net::ReadTimeout with #")).then + .to_return(status: 200, body: '[{"id":1}]') + + expect { request.get("/partner/documents/") }.not_to raise_error + end + + it "re-raises Faraday::TimeoutError when the socket is not closed" do + stub_request(:get, endpoint) + .to_raise(Faraday::TimeoutError.new("execution expired")) + + expect { request.get("/partner/documents/") }.to raise_error(Faraday::TimeoutError, /execution expired/) + end + end + context "when server responds with empty body" do before do stub_request(:get, /\.*/).to_return(status: 501, body: "") diff --git a/spec/veryfi_spec.rb b/spec/veryfi_spec.rb index 796a33d..5223d5b 100644 --- a/spec/veryfi_spec.rb +++ b/spec/veryfi_spec.rb @@ -26,7 +26,7 @@ it "exposes sensible defaults" do expect(described_class.configuration.base_url).to eq("https://api.veryfi.com/api/") expect(described_class.configuration.api_version).to eq("v8") - expect(described_class.configuration.timeout).to eq(20) + expect(described_class.configuration.timeout).to eq(30) end end