Commit af77e1cf authored by allison.browne's avatar allison.browne

Extract auto retry logic out of build model

Adds a new Gitlab::Ci::Build::AutoRetry class with
the new retry logic. Moves the original build model
specs and makes them pass in the new location.
parent a6e27643
class Gitlab::Ci::Build::AutoRetry
include Gitlab::Utils::StrongMemoize
DEFAULT_RETRIES = {
scheduler_failure: 2
}.freeze
def initialize(build)
@build = build
end
def allowed?
# return false unless build.retryable?
within_max_retry_limit?
end
private
def within_max_retry_limit?
max_allowed_retries > 0 && max_allowed_retries > @build.retries_count
end
def max_allowed_retries
strong_memoize(:options_retry) do
options_retry_max || DEFAULT_RETRIES.fetch(@build.failure_reason.to_sym, 0)
end
end
def options_retry_max
options_retry[:max] if retry_on_reason_or_always?
end
def options_retry_when
options_retry.fetch(:when, ['always'])
end
def retry_on_reason_or_always?
options_retry_when.include?(@build.failure_reason.to_s) ||
options_retry_when.include?('always')
end
# The format of the retry option changed in GitLab 11.5: Before it was
# integer only, after it is a hash. New builds are created with the new
# format, but builds created before GitLab 11.5 and saved in database still
# have the old integer only format. This method returns the retry option
# normalized as a hash in 11.5+ format.
def options_retry
strong_memoize(:options_retry) do
value = @build.options&.dig(:retry)
value = value.is_a?(Integer) ? { max: value } : value.to_h
value.with_indifferent_access
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Ci::Build::AutoRetry do
describe '#within_max_retry_limit?' do
using RSpec::Parameterized::TableSyntax
let(:build) { create(:ci_build) }
subject { Gitlab::Ci::Build::AutoRetry.new(build).allowed? }
where(:description, :retry_count, :options, :failure_reason, :result) do
"retries are disabled" | 0 | { max: 0 } | nil | false
"max equals count" | 2 | { max: 2 } | nil | false
"max is higher than count" | 1 | { max: 2 } | nil | true
"matching failure reason" | 0 | { when: %w[api_failure], max: 2 } | :api_failure | true
"not matching with always" | 0 | { when: %w[always], max: 2 } | :api_failure | true
"not matching reason" | 0 | { when: %w[script_error], max: 2 } | :api_failure | false
"scheduler failure override" | 1 | { when: %w[scheduler_failure], max: 1 } | :scheduler_failure | false
"default for scheduler failure" | 1 | {} | :scheduler_failure | true
end
with_them do
before do
allow(build).to receive(:retries_count) { retry_count }
build.options[:retry] = options
build.failure_reason = failure_reason
end
it { is_expected.to eq(result) }
end
end
end
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment