diff options
Diffstat (limited to 'lib/bulk_imports/network_error.rb')
-rw-r--r-- | lib/bulk_imports/network_error.rb | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/lib/bulk_imports/network_error.rb b/lib/bulk_imports/network_error.rb new file mode 100644 index 00000000000..d69b0172f6c --- /dev/null +++ b/lib/bulk_imports/network_error.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +module BulkImports + class NetworkError < Error + COUNTER_KEY = 'bulk_imports/%{entity_id}/%{stage}/%{tracker_id}/network_error/%{error}' + + RETRIABLE_EXCEPTIONS = Gitlab::HTTP::HTTP_TIMEOUT_ERRORS + RETRIABLE_HTTP_CODES = [429].freeze + + DEFAULT_RETRY_DELAY_SECONDS = 60 + + MAX_RETRIABLE_COUNT = 3 + + def initialize(message = nil, response: nil) + raise ArgumentError, 'message or response required' if message.blank? && response.blank? + + super(message) + + @response = response + end + + def retriable?(tracker) + if retriable_exception? || retriable_http_code? + increment(tracker) <= MAX_RETRIABLE_COUNT + else + false + end + end + + def retry_delay + if response&.code == 429 + response.headers.fetch('Retry-After', DEFAULT_RETRY_DELAY_SECONDS).to_i + else + DEFAULT_RETRY_DELAY_SECONDS + end.seconds + end + + private + + attr_reader :response + + def retriable_exception? + RETRIABLE_EXCEPTIONS.include?(cause&.class) + end + + def retriable_http_code? + RETRIABLE_HTTP_CODES.include?(response&.code) + end + + def increment(tracker) + key = COUNTER_KEY % { + stage: tracker.stage, + tracker_id: tracker.id, + entity_id: tracker.entity.id, + error: cause.class.name + } + + Gitlab::Cache::Import::Caching.increment(key) + end + end +end |