From 4d929f984b8c094c5ea99b5be68a1066609510ec Mon Sep 17 00:00:00 2001 From: Andres Garcia Date: Fri, 3 Jul 2026 11:04:17 -0500 Subject: [PATCH 1/4] Increase timeout to 30 seconds and implement stale connection recovery in Veryfi::Request. Update version to 4.0.1. --- lib/veryfi/client.rb | 2 +- lib/veryfi/configuration.rb | 2 +- lib/veryfi/request.rb | 10 +++++++++- lib/veryfi/version.rb | 2 +- spec/veryfi/request_spec.rb | 35 +++++++++++++++++++++++++++++++++++ spec/veryfi_spec.rb | 2 +- 6 files changed, 48 insertions(+), 5 deletions(-) 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..9464c96 100644 --- a/lib/veryfi/request.rb +++ b/lib/veryfi/request.rb @@ -65,7 +65,15 @@ def make_request(http_verb, path, params = {}) body = generate_body(http_verb, params) headers = generate_headers(params) - response = conn.public_send(http_verb, url, body, headers) + begin + response = conn.public_send(http_verb, url, body, headers) + rescue Net::ReadTimeout => e + raise unless e.message.include?("closed") + + @_conn = nil + response = conn.public_send(http_verb, url, body, headers) + end + json_response = process_response(response) if response.success? 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..109e4a9 100644 --- a/spec/veryfi/request_spec.rb +++ b/spec/veryfi/request_spec.rb @@ -94,6 +94,41 @@ end end + describe "stale connection recovery" do + it "resets the cached connection and retries when Net::ReadTimeout is raised with a closed socket" do + request = Veryfi::Request.new("cid", nil, "u", "k", + "https://api.veryfi.com/api/", "v8", 30) + + call_count = 0 + fake_conn = instance_double(Faraday::Connection) + allow(fake_conn).to receive(:get) do + call_count += 1 + raise Net::ReadTimeout, "#" if call_count == 1 + + instance_double(Faraday::Response, success?: true, body: '{"id":1}', status: 200) + end + + allow(request).to receive(:conn).and_wrap_original do |original| + call_count.zero? ? fake_conn : fake_conn + end + allow(request).to receive(:conn).and_return(fake_conn) + + expect { request.get("/partner/documents/") }.not_to raise_error + expect(call_count).to eq(2) + end + + it "re-raises Net::ReadTimeout when the socket is not closed" do + request = Veryfi::Request.new("cid", nil, "u", "k", + "https://api.veryfi.com/api/", "v8", 30) + + fake_conn = instance_double(Faraday::Connection) + allow(fake_conn).to receive(:get).and_raise(Net::ReadTimeout, "execution expired") + allow(request).to receive(:conn).and_return(fake_conn) + + expect { request.get("/partner/documents/") }.to raise_error(Net::ReadTimeout, /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 From 08d12c2507ddd9aa304db17019a2516a6753eb4a Mon Sep 17 00:00:00 2001 From: Andres Garcia Date: Fri, 3 Jul 2026 14:14:15 -0500 Subject: [PATCH 2/4] Update veryfi gem version to 4.0.1 in Gemfile.lock --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 97e30d8..9723af5 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) From 6b2f4bbe0ffe29e42b326bba2a503bf4b4b83e63 Mon Sep 17 00:00:00 2001 From: Andres Garcia Date: Fri, 3 Jul 2026 14:20:46 -0500 Subject: [PATCH 3/4] Refactor Veryfi::Request to centralize request handling and improve stale connection recovery. Introduce attempt_request method to manage retries on Faraday::TimeoutError. Update tests to reflect new error handling behavior. --- lib/veryfi/request.rb | 20 ++++++++++---------- spec/veryfi/request_spec.rb | 36 ++++++++++++------------------------ 2 files changed, 22 insertions(+), 34 deletions(-) diff --git a/lib/veryfi/request.rb b/lib/veryfi/request.rb index 9464c96..f3a7790 100644 --- a/lib/veryfi/request.rb +++ b/lib/veryfi/request.rb @@ -64,16 +64,7 @@ def make_request(http_verb, path, params = {}) url = [api_url, path].join body = generate_body(http_verb, params) headers = generate_headers(params) - - begin - response = conn.public_send(http_verb, url, body, headers) - rescue Net::ReadTimeout => e - raise unless e.message.include?("closed") - - @_conn = nil - response = conn.public_send(http_verb, url, body, headers) - end - + response = attempt_request(http_verb, url, body, headers) json_response = process_response(response) if response.success? @@ -83,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/spec/veryfi/request_spec.rb b/spec/veryfi/request_spec.rb index 109e4a9..3337af3 100644 --- a/spec/veryfi/request_spec.rb +++ b/spec/veryfi/request_spec.rb @@ -95,37 +95,25 @@ end describe "stale connection recovery" do - it "resets the cached connection and retries when Net::ReadTimeout is raised with a closed socket" do - request = Veryfi::Request.new("cid", nil, "u", "k", - "https://api.veryfi.com/api/", "v8", 30) - - call_count = 0 - fake_conn = instance_double(Faraday::Connection) - allow(fake_conn).to receive(:get) do - call_count += 1 - raise Net::ReadTimeout, "#" if call_count == 1 + let(:request) do + described_class.new("cid", nil, "u", "k", "https://api.veryfi.com/api/", "v8", 30) + end - instance_double(Faraday::Response, success?: true, body: '{"id":1}', status: 200) - end + let(:endpoint) { "https://api.veryfi.com/api/v8/partner/documents/" } - allow(request).to receive(:conn).and_wrap_original do |original| - call_count.zero? ? fake_conn : fake_conn - end - allow(request).to receive(:conn).and_return(fake_conn) + 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 - expect(call_count).to eq(2) end - it "re-raises Net::ReadTimeout when the socket is not closed" do - request = Veryfi::Request.new("cid", nil, "u", "k", - "https://api.veryfi.com/api/", "v8", 30) - - fake_conn = instance_double(Faraday::Connection) - allow(fake_conn).to receive(:get).and_raise(Net::ReadTimeout, "execution expired") - allow(request).to receive(:conn).and_return(fake_conn) + 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(Net::ReadTimeout, /execution expired/) + expect { request.get("/partner/documents/") }.to raise_error(Faraday::TimeoutError, /execution expired/) end end From eaf0f9a2d49b32fbd45adc52c2ad52de8727f07d Mon Sep 17 00:00:00 2001 From: Andres Garcia Date: Fri, 3 Jul 2026 15:01:45 -0500 Subject: [PATCH 4/4] Update dependencies in Gemfile.lock: bump faraday to 2.14.3, faraday-net_http to 3.4.4, and json to 2.20.0 for improved compatibility and security. --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9723af5..a05a20a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -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)