Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/.bundle/
/.yardoc
/Gemfile.lock
/_yardoc/
/coverage/
/doc/
Expand Down
3 changes: 2 additions & 1 deletion .hound.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
ruby:
config_file: .rubocop.yml
# config_file: .rubocop.yml
enabled: false
52 changes: 39 additions & 13 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
Style/StringLiterals:
EnforcedStyle: double_quotes
AllCops:
TargetRubyVersion: 2.0

Style/Documentation:
Enabled: false
Layout/IndentArray:
EnforcedStyle: consistent

Layout/SpaceAroundOperators:
AllowForAlignment: true

Style/TrailingCommaInArguments:
EnforcedStyleForMultiline: comma

Lint/InheritException:
Exclude:
- 'spec/support/exceptions.rb'


Metrics/AbcSize:
Enabled: false

Layout/IndentArray:
Metrics/BlockLength:
Enabled: false

Layout/IndentHash:
Metrics/ClassLength:
Enabled: false

Style/NegatedIf:
Metrics/CyclomaticComplexity:
Enabled: false

Metrics/ClassLength:
Metrics/MethodLength:
Enabled: false

Metrics/ModuleLength:
Expand All @@ -28,11 +34,31 @@ Metrics/ModuleLength:
Metrics/LineLength:
Max: 120

Metrics/MethodLength:
Metrics/PerceivedComplexity:
Enabled: false

Metrics/BlockLength:

RSpec/ExampleLength:
Enabled: false

Metrics/AbcSize:
RSpec/FilePath:
# rspec thinks these should be in spec/retriable/
# There is a SpecSuffixOnly option that should fix this
# but it's being silently ignored
Exclude:
- 'spec/config_spec.rb'
- 'spec/exponential_backoff_spec.rb'

RSpec/InstanceVariable:
Exclude:
- 'spec/retriable_spec.rb'


Style/Documentation:
Enabled: false

Style/NegatedIf:
Enabled: false

Style/TrailingCommaInArguments:
EnforcedStyleForMultiline: comma
8 changes: 5 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Send builds to container-based infrastructure
# http://docs.travis-ci.com/user/workers/container-based-infrastructure/
dist: trusty
dist: xenial
language: ruby
rvm:
- 2.0.0
Expand All @@ -10,6 +10,8 @@ rvm:
- 2.4.6
- 2.5.5
- 2.6.2
- 2.7
- 3.0
- ruby-head
- jruby-9.2.9.0
- jruby-head
Expand All @@ -24,16 +26,16 @@ env:
- CC_TEST_REPORTER_ID=20a1139ef1830b4f813a10a03d90e8aa179b5226f75e75c5a949b25756ebf558

before_install:
- gem install rubygems-update -v '<3' --no-document && update_rubygems
- gem install bundler -v 1.17.3
- bundle install

before_script:
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
- chmod +x ./cc-test-reporter
- ./cc-test-reporter before-build

script:
- bundle exec rspec
- bundle exec rake test:ci

after_script:
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
21 changes: 15 additions & 6 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
source "https://rubygems.org"
# frozen_string_literal: true

source 'https://rubygems.org'

gemspec

group :test do
gem "rspec"
gem "simplecov", require: false
gem 'rspec'
gem 'simplecov', require: false
end

group :development do
gem "rubocop"
group :development, :test do
gem 'rubocop', '>= 0.50', '< 0.51', require: false
gem 'rubocop-rspec', require: false
end

group :development, :test do
gem "pry"
gem 'jazz_fingers'
gem 'rake'
# byebug constraint due to lack of support for binding.local_variables
# in ruby 2.0
gem 'byebug', '< 9.0.0'
# pry constraints fix https://github.com/pry/pry/issues/2121
gem 'pry', '!= 0.13.0', '!= 0.13.1'
end
98 changes: 98 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
PATH
remote: .
specs:
retriable (3.1.2)

GEM
remote: https://rubygems.org/
specs:
ast (2.4.2)
awesome_print (1.8.0)
byebug (8.2.5)
coderay (1.1.3)
coolline (0.5.0)
unicode_utils (~> 1.4)
diff-lcs (1.4.4)
docile (1.3.5)
hirb (0.7.3)
jazz_fingers (3.0.1)
awesome_print (~> 1.6)
hirb (~> 0.7)
pry (~> 0.10)
pry-byebug (~> 3.1)
pry-coolline (~> 0.2)
pry-doc (~> 0.6)
pry-remote (>= 0.1.7)
json (2.5.1)
method_source (0.9.2)
parallel (1.13.0)
parser (2.7.2.0)
ast (~> 2.4.1)
powerpack (0.1.3)
pry (0.12.2)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
pry-byebug (3.3.0)
byebug (~> 8.0)
pry (~> 0.10)
pry-coolline (0.2.5)
coolline (~> 0.5)
pry-doc (0.13.5)
pry (~> 0.11)
yard (~> 0.9.11)
pry-remote (0.1.8)
pry (~> 0.9)
slop (~> 3.0)
rainbow (2.2.2)
rake
rake (12.3.3)
rspec (3.10.0)
rspec-core (~> 3.10.0)
rspec-expectations (~> 3.10.0)
rspec-mocks (~> 3.10.0)
rspec-core (3.10.1)
rspec-support (~> 3.10.0)
rspec-expectations (3.10.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0)
rspec-mocks (3.10.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0)
rspec-support (3.10.1)
rubocop (0.50.0)
parallel (~> 1.10)
parser (>= 2.3.3.1, < 3.0)
powerpack (~> 0.1)
rainbow (>= 2.2.2, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
rubocop-rspec (1.5.1)
rubocop (>= 0.41.2)
ruby-progressbar (1.11.0)
simplecov (0.17.1)
docile (~> 1.1)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
slop (3.6.0)
unicode-display_width (1.7.0)
unicode_utils (1.4.0)
yard (0.9.26)

PLATFORMS
ruby

DEPENDENCIES
bundler
byebug (< 9.0.0)
jazz_fingers
pry (!= 0.13.1, != 0.13.0)
rake
retriable!
rspec
rubocop (>= 0.50, < 0.51)
rubocop-rspec
simplecov

BUNDLED WITH
1.17.3
38 changes: 38 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
require 'bundler/setup'
Bundler.require(:test, :development)

begin
require 'rspec/core/rake_task'
require 'rubocop/rake_task'
rescue LoadError => e
require 'shellwords'
raise "Required gem #{e.path.inspect} not found. " \
'Be sure you ran `bundle install` and are launching rake via ' \
"`bundle exec rake #{ARGV.shelljoin}`."
end

namespace :test do
RSpec::Core::RakeTask.new(:rspec) do |t|
t.rspec_opts = '-w --backtrace --no-fail-fast'
end

RuboCop::RakeTask.new('rubocop') do |t, _task_args|
t.options << '--require' << 'rubocop-rspec'
t.options << '--fail-level' << 'convention'
t.options << '--display-cop-names'
t.options << '--extra-details'
t.options << '--display-style-guide'
# Can't enable parallel because it will break rubocop:autocorrect
# t.options << '--parallel'
end

desc 'Run all tests'
task all: %w[test:rubocop test:rspec]

task ci: %w[test:all]
end

desc 'Alias for test:all'
task test: %w[test:all]

task default: %w[test]
57 changes: 38 additions & 19 deletions lib/retriable.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require "timeout"
require_relative "retriable/config"
require_relative "retriable/exponential_backoff"
require_relative "retriable/version"
require 'timeout'
require_relative 'retriable/config'
require_relative 'retriable/exponential_backoff'
require_relative 'retriable/version'

module Retriable
module_function
Expand All @@ -15,8 +15,9 @@ def config
end

def with_context(context_key, options = {}, &block)
if !config.contexts.key?(context_key)
raise ArgumentError, "#{context_key} not found in Retriable.config.contexts. Available contexts: #{config.contexts.keys}"
unless config.contexts.key?(context_key)
raise ArgumentError, "#{context_key} not found in Retriable.config.contexts. "\
"Available contexts: #{config.contexts.keys}"
end

retriable(config.contexts[context_key].merge(options), &block) if block
Expand All @@ -42,35 +43,53 @@ def retriable(opts = {})
elapsed_time = -> { Time.now - start_time }

if intervals
tries = intervals.size + 1
tries = intervals.size + 1 if intervals.size
else
intervals = ExponentialBackoff.new(
tries: tries - 1,
backoff = ExponentialBackoff.new(
tries: tries ? tries - 1 : nil,
base_interval: base_interval,
multiplier: multiplier,
max_interval: max_interval,
rand_factor: rand_factor
).intervals
rand_factor: rand_factor,
)
intervals = backoff.intervals
end

tries.times do |index|
try = index + 1

# TODO: Ideally this would be it's own function, but would probably require
# a separate class to efficiently pass on the processed config
run_try = proc do |interval, try|
begin
return Timeout.timeout(timeout) { return yield(try) } if timeout
return yield(try)
rescue *[*exception_list] => exception
rescue *exception_list => exception
if on.is_a?(Hash)
raise unless exception_list.any? do |e|
exception.is_a?(e) && ([*on[e]].empty? || [*on[e]].any? { |pattern| exception.message =~ pattern })
end
end

interval = intervals[index]
on_retry.call(exception, try, elapsed_time.call, interval) if on_retry
raise if try >= tries || (elapsed_time.call + interval) > max_elapsed_time
sleep interval if sleep_disabled != true

# Note: Tries can't always be calculated if a custom Enumerator is given
# for the intervals argument. (Enumerator#size will return nil, per docs)
# So we'll just let the enumerator run out, and then invoke run_try once more.
# With a nil timeout.
raise unless interval
raise if max_elapsed_time && elapsed_time.call + interval > max_elapsed_time
sleep interval unless sleep_disabled
throw :failed
end
end

try = 0
intervals.each do |interval|
try += 1
# Use throw/catch to distinguish between success and caught exception
catch :failed do
result = run_try.call(interval, try)
return result
end
break if tries && (try + 1 >= tries)
end
run_try.call(nil, try + 1)
end
end
Loading