diff --git a/app/jobs/champ_fetch_external_data_job.rb b/app/jobs/champ_fetch_external_data_job.rb index 790052863..4e11bd96a 100644 --- a/app/jobs/champ_fetch_external_data_job.rb +++ b/app/jobs/champ_fetch_external_data_job.rb @@ -1,9 +1,28 @@ class ChampFetchExternalDataJob < ApplicationJob + include Dry::Monads[:result] + def perform(champ, external_id) return if champ.external_id != external_id return if champ.data.present? - return if (data = champ.fetch_external_data).blank? - champ.update_with_external_data!(data: data) + Sentry.set_tags(champ: champ.id) + Sentry.set_extras(external_id:) + + result = champ.fetch_external_data + + if result.is_a?(Dry::Monads::Result) + case result + in Success(data) + champ.update_with_external_data!(data:) + in Failure(retryable: true, reason:) + champ.log_fetch_external_data_exception(reason) + throw reason + in Failure(retryable: false, reason:) + champ.log_fetch_external_data_exception(reason) + Sentry.capture_exception(reason) + end + elsif result.present? + champ.update_with_external_data!(data: result) + end end end diff --git a/spec/jobs/champ_fetch_external_data_job_spec.rb b/spec/jobs/champ_fetch_external_data_job_spec.rb index 6f5277727..a4f75cc67 100644 --- a/spec/jobs/champ_fetch_external_data_job_spec.rb +++ b/spec/jobs/champ_fetch_external_data_job_spec.rb @@ -3,17 +3,21 @@ require 'rails_helper' RSpec.describe ChampFetchExternalDataJob, type: :job do - let(:champ) { Struct.new(:external_id, :data).new(champ_external_id, data) } + let(:champ) { build(:champ, external_id: champ_external_id, data:) } let(:external_id) { "an ID" } let(:champ_external_id) { "an ID" } let(:data) { nil } let(:fetched_data) { nil } + let(:reason) { StandardError.new("error") } subject(:perform_job) { described_class.perform_now(champ, external_id) } + include Dry::Monads[:result] + before do allow(champ).to receive(:fetch_external_data).and_return(fetched_data) allow(champ).to receive(:update_with_external_data!) + allow(champ).to receive(:log_fetch_external_data_exception) end shared_examples "a champ non-updater" do @@ -38,6 +42,35 @@ RSpec.describe ChampFetchExternalDataJob, type: :job do end end + context 'when the fetched data is a result' do + context 'success' do + let(:fetched_data) { Success("data") } + + it 'updates the champ' do + perform_job + expect(champ).to have_received(:update_with_external_data!).with(data: fetched_data.value!) + end + end + + context 'retryable failure' do + let(:fetched_data) { Failure(API::Client::Error[:http, 400, true, reason]) } + + it 'saves exception and raise' do + expect { perform_job }.to raise_error StandardError + expect(champ).to have_received(:log_fetch_external_data_exception).with(reason) + end + end + + context 'fatal failure' do + let(:fetched_data) { Failure(API::Client::Error[:http, 400, false, reason]) } + + it 'saves exception' do + perform_job + expect(champ).to have_received(:log_fetch_external_data_exception).with(reason) + end + end + end + context 'when the fetched data is blank' do it_behaves_like "a champ non-updater" end