diff --git a/app/services/persona/api_service.rb b/app/services/persona/api_service.rb index 0c6ce35e..7e134a24 100644 --- a/app/services/persona/api_service.rb +++ b/app/services/persona/api_service.rb @@ -146,6 +146,11 @@ def connection request: { timeout: 30, open_timeout: 10 } ) do |f| f.request :json + # persona throws the odd 5xx mid-fetch; one blip on the selfie lookup + # used to drop the liveness photos for good, since a saved document + # stops ensure_inquiry_data_saved from ever refetching. retry only + # touches idempotent methods, so creates/updates never double-fire. + f.request :retry, max: 2, interval: 0.5, backoff_factor: 2, retry_statuses: [ 502, 503, 504 ] f.response :json f.adapter Faraday.default_adapter end diff --git a/spec/services/persona/api_service_spec.rb b/spec/services/persona/api_service_spec.rb index b0deba0a..7c50f23e 100644 --- a/spec/services/persona/api_service_spec.rb +++ b/spec/services/persona/api_service_spec.rb @@ -214,6 +214,33 @@ expect(result.liveness.map { |l| l[:label] }).to contain_exactly("selfie_center", "selfie_left", "selfie_right") end + it "retries a transient 503 before giving up on the selfie" do + stub = stub_request(:get, "#{base_url}/api/v1/verification/selfies/ver_selfie123") + .to_return({ status: 503, body: "" }) + .then.to_return( + status: 200, + headers: { "Content-Type" => "application/json" }, + body: { data: { id: "ver_selfie123", type: "verification/selfie", attributes: { + center_photo_url: "https://files.withpersona.com/center.jpg" + } }, meta: {} }.to_json + ) + + result = service.retrieve_verification_photos("ver_selfie123", type: "verification/selfie") + + expect(stub).to have_been_requested.twice + expect(result.liveness.map { |l| l[:label] }).to eq([ "selfie_center" ]) + end + + it "raises Persona::APIError once 503 retries are exhausted" do + stub = stub_request(:get, "#{base_url}/api/v1/verification/selfies/ver_selfie123") + .to_return(status: 503, body: "") + + expect { + service.retrieve_verification_photos("ver_selfie123", type: "verification/selfie") + }.to raise_error(Persona::APIError, /503/) + expect(stub).to have_been_requested.times(3) + end + it "returns empty PhotoSet for non-selfie verifications" do result = service.retrieve_verification_photos("ver_gov123", type: "verification/government-id")