diff --git a/lib/sequencer/unit/import/zendesk/sub_sequence/base.rb b/lib/sequencer/unit/import/zendesk/sub_sequence/base.rb index 6e949f351..ac25648a9 100644 --- a/lib/sequencer/unit/import/zendesk/sub_sequence/base.rb +++ b/lib/sequencer/unit/import/zendesk/sub_sequence/base.rb @@ -41,23 +41,31 @@ class Sequencer def resource_iteration(&block) resource_collection.public_send(resource_iteration_method, &block) rescue ZendeskAPI::Error::NetworkError => e + return if expected_exception?(e) + raise if !retry_exception?(e) + raise if (fail_count ||= 1) > 10 + + logger.error e + logger.info "Sleeping 10 seconds after ZendeskAPI::Error::NetworkError and retry (##{fail_count}/10)." + sleep 10 + + fail_count += 1 + retry + end + + # #2262 Zendesk-Import fails for User & Organizations when 403 "access" denied + def expected_exception?(e) status = e.response.status.to_s + return false if status != '403' - if status.match?(/^(4|5)\d\d$/) + %w[UserField OrganizationField].include?(resource_klass) + end - # #2262 Zendesk-Import fails for User & Organizations when 403 "access" denied - return if status == '403' && resource_klass.in?(%w[UserField OrganizationField]) + def retry_exception?(e) + return true if e.message.include?('execution expired') - raise if (fail_count ||= 1) > 10 - - logger.error e - logger.info "Sleeping 10 seconds after ZendeskAPI::Error::NetworkError and retry (##{fail_count}/10)." - sleep 10 - - (fail_count += 1) && retry - end - - raise + status = e.response.status.to_s + status.match?(/^(4|5)\d\d$/) end def resource_collection diff --git a/spec/lib/sequencer/unit/import/zendesk/sub_sequence/base_examples.rb b/spec/lib/sequencer/unit/import/zendesk/sub_sequence/base_examples.rb index 0dc462250..23a95100c 100644 --- a/spec/lib/sequencer/unit/import/zendesk/sub_sequence/base_examples.rb +++ b/spec/lib/sequencer/unit/import/zendesk/sub_sequence/base_examples.rb @@ -26,7 +26,8 @@ RSpec.shared_examples 'Sequencer::Unit::Import::Zendesk::SubSequence::Base' do let(:collection_name) { described_class.name.demodulize.snakecase.to_sym } let(:client_collection) { double('ZendeskAPI::Collection') } - let(:api_error) { ZendeskAPI::Error::NetworkError.new('Mock err msg', response_obj) } + let(:api_error_message) { 'Mock err msg' } + let(:api_error) { ZendeskAPI::Error::NetworkError.new(api_error_message, response_obj) } let(:response_obj) do # stubbed methods required for ZendeskAPI::Error::ClientError#to_s @@ -90,5 +91,17 @@ RSpec.shared_examples 'Sequencer::Unit::Import::Zendesk::SubSequence::Base' do end.to raise_error(api_error) end end + + context 'when execution timeout occurs' do + let(:api_error_message) { "execution expired -- get https://example.zendesk.com/api/v2/#{collection_name}" } + + it 'retries ten times, in 10s intervals' do + expect do + process(params) do |unit| + expect(unit).to receive(:sleep).with(10).exactly(10).times + end + end.to raise_error(api_error) + end + end end end