class Bosh::Retryable
Public Class Methods
new(options = {})
click to toggle source
# File lib/common/retryable.rb, line 5 def initialize(options = {}) opts = validate_options(options) @ensure_callback = opts[:ensure] @matching = opts[:matching] @try_count = 0 @retry_exception = nil @retry_limit = opts[:tries] @sleeper = opts[:sleep] @matchers = Array(opts[:on]).map do |klass_or_matcher| if klass_or_matcher.is_a?(Class) ErrorMatcher.by_class(klass_or_matcher) else klass_or_matcher end end end
Public Instance Methods
retryer(&blk)
click to toggle source
Loops until the block returns a true value
# File lib/common/retryable.rb, line 25 def retryer(&blk) loop do @try_count += 1 y = blk.call(@try_count, @retry_exception) @retry_exception = nil # no exception was raised in the block return y if y raise Bosh::Common::RetryCountExceeded if @try_count >= @retry_limit wait end rescue Exception => exception raise unless @matchers.any? { |m| m.matches?(exception) } raise unless exception.message =~ @matching raise if @try_count >= @retry_limit @retry_exception = exception wait retry ensure @ensure_callback.call(@try_count) end
Private Instance Methods
default_options()
click to toggle source
# File lib/common/retryable.rb, line 55 def default_options { tries: 2, sleep: exponential_sleeper, on: [], matching: /.*/, ensure: Proc.new {}, } end
exponential_sleeper()
click to toggle source
# File lib/common/retryable.rb, line 73 def exponential_sleeper lambda { |tries, _| [2**(tries-1), 10].min } # 1, 2, 4, 8, 10, 10..10 seconds end
sleep(*args, &blk)
click to toggle source
# File lib/common/retryable.rb, line 77 def sleep(*args, &blk) Kernel.sleep(*args, &blk) end
validate_options(options)
click to toggle source
# File lib/common/retryable.rb, line 48 def validate_options(options) merged_options = default_options.merge(options) invalid_options = merged_options.keys - default_options.keys raise ArgumentError.new("Invalid options: #{invalid_options.join(", ")}") unless invalid_options.empty? merged_options end
wait()
click to toggle source
# File lib/common/retryable.rb, line 65 def wait sleep(@sleeper.respond_to?(:call) ? @sleeper.call(@try_count, @retry_exception) : @sleeper) rescue Exception => exception raise unless @matchers.any? { |m| m.matches?(exception) } # SignalException could be raised while sleeping, so if you want to catch it, # it need to be passed in the list of exceptions to ignore end