retriable 2.0.0.beta5 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a7f89877bb9506abc02a59892b97c55a0f995b38
4
- data.tar.gz: 7b9e325e86386e6e0e739bb4a51df12882327c1b
3
+ metadata.gz: 1b752911d256dced83d90ff384285f521001fd21
4
+ data.tar.gz: bc8abdb30075bfe7948bff5e2a7ddec0cdeb62ac
5
5
  SHA512:
6
- metadata.gz: 4fc3260da9272d6fe2a8b29c939ea661e49cb45d28b7a082021a44d6823c96d1612860d6a8cdfe5acc0973c0bdbbeeaa55869f0831999396826b2653c47a29c2
7
- data.tar.gz: 11113a95d8b63b1bed523f0fd98755dd9b4a176435b40a3cbf877d5eabd136e30aec8eba5ee9b3369d8c1af3311f8883910f7965d19747b077e3dbf9ab867b50
6
+ metadata.gz: b564835a63aa4d7e890cc0417d55132a8124070b92747074d9c5795daf28d2cc896cdc887e1da31b6176ee4061a83c9513b47dc15171f1332c1b0f40d4f59752
7
+ data.tar.gz: 7560dac587dfc6556602117c3f698ce2a7e52ef00f465e9a1dc871e7faf8a764d220a6ef8a34fb16dd2a45c278c9965043664cec4d300bf6a508bbd4d121480a
data/.gitignore CHANGED
@@ -1,7 +1,14 @@
1
- .DS_Store
2
- .rvmrc
3
- *.gem
4
- .bundle
5
- Gemfile.lock
6
- pkg/*
7
- .idea
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
@@ -1,10 +1,17 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 2.0.0
4
- - 2.1.3
5
- - jruby
4
+ - 2.1.5
5
+ - 2.2.0
6
6
  - rbx
7
+ - ruby-head
8
+ - jruby-head
7
9
 
8
10
  matrix:
9
11
  allow_failures:
10
- - rvm: jruby
12
+ - rvm: ruby-head
13
+ - rvm: jruby-head
14
+
15
+ addons:
16
+ code_climate:
17
+ repo_token: 20a1139ef1830b4f813a10a03d90e8aa179b5226f75e75c5a949b25756ebf558
@@ -1,5 +1,9 @@
1
+ ## HEAD
2
+
3
+ * Require ruby 2.0.0 minimum in gemspec.
4
+
1
5
  ## 2.0.0.beta5
2
- * Change :max_tries back to :tries.
6
+ * Change `:max_tries` back to `:tries`.
3
7
 
4
8
  ## 2.0.0.beta4
5
9
  * Change #retry back to #retriable. Didn't like the idea of defining a method that is also a reserved word.
data/Gemfile CHANGED
@@ -2,3 +2,15 @@ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in retriable.gemspec
4
4
  gemspec
5
+
6
+ group :test do
7
+ gem "ruby_gntp"
8
+ gem "minitest-focus"
9
+ gem "codeclimate-test-reporter", require: false
10
+ gem "simplecov", require: false
11
+ end
12
+
13
+ group :development, :test do
14
+ gem "pry"
15
+ gem "awesome_print"
16
+ end
data/Guardfile CHANGED
@@ -2,13 +2,7 @@
2
2
  # More info at https://github.com/guard/guard#readme
3
3
 
4
4
  guard :minitest do
5
- # with Minitest::Unit
6
- watch(%r{^test/(.*)\/?test_(.*)\.rb})
7
- watch(%r{^lib/retriable/(.*/)?([^/]+)\.rb}) { |m| "test/#{m[1]}/test_#{m[2]}.rb" }
8
- watch(%r{^test/test_helper\.rb}) { 'test' }
9
-
10
- # with Minitest::Spec
11
5
  watch(%r{^spec/(.*)_spec\.rb})
12
- watch(%r{^lib/retriable/(.+)\.rb}) { |m| "spec/#{m[1]}_spec.rb" }
13
- watch(%r{^spec/spec_helper\.rb}) { 'spec' }
6
+ watch(%r{^lib/retriable/(.+)\.rb}) { |m| "spec/#{m[1]}_spec.rb" }
7
+ watch(%r{^spec/spec_helper\.rb}) { 'spec' }
14
8
  end
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  #Retriable
2
2
 
3
3
  [![Build Status](https://secure.travis-ci.org/kamui/retriable.png)](http://travis-ci.org/kamui/retriable)
4
+ [![Code Climate](https://codeclimate.com/github/kamui/retriable/badges/gpa.svg)](https://codeclimate.com/github/kamui/retriable)
5
+ [![Test Coverage](https://codeclimate.com/github/kamui/retriable/badges/coverage.svg)](https://codeclimate.com/github/kamui/retriable)
4
6
 
5
7
  Retriable is an simple DSL to retry failed code blocks with randomized [exponential backoff](http://en.wikipedia.org/wiki/Exponential_backoff) time intervals. This is especially useful when interacting external api/services or file system calls.
6
8
 
@@ -23,31 +25,31 @@ gem install retriable
23
25
  In your ruby script:
24
26
 
25
27
  ```ruby
26
- require 'retriable', '~> 2.0'
28
+ require 'retriable'
27
29
  ```
28
30
 
29
31
  In your Gemfile:
30
32
 
31
33
  ```ruby
32
- gem 'retriable'
34
+ gem 'retriable', '~> 2.0'
33
35
  ```
34
36
 
35
37
  ## Usage
36
38
 
37
- Code in a `Retriable.retriable` block will be retried if an exception is raised. By default, Retriable will rescue any exception inherited from `StandardError`, make 3 retry attempts before raising the last exception, and also use randomized exponential backoff to calculate each succeeding attempt interval. The default interval table with 10 attempts looks like this (in seconds):
39
+ Code in a `Retriable.retriable` block will be retried if an exception is raised. By default, Retriable will rescue any exception inherited from `StandardError`, make 3 retry tries before raising the last exception, and also use randomized exponential backoff to calculate each succeeding try interval. The default interval table with 10 tries looks like this (in seconds):
38
40
 
39
- | request# | retry interval | randomized interval |
40
- | -------- | -------------- | ------------------- |
41
- | 1 | 0.5 | [0.25, 0.75] |
42
- | 2 | 0.75 | [0.375, 1.125] |
43
- | 3 | 1.125 | [0.562, 1.687] |
44
- | 4 | 1.687 | [0.8435, 2.53] |
45
- | 5 | 2.53 | [1.265, 3.795] |
46
- | 6 | 3.795 | [1.897, 5.692] |
47
- | 7 | 5.692 | [2.846, 8.538] |
48
- | 8 | 8.538 | [4.269, 12.807] |
49
- | 9 | 12.807 | [6.403, 19.210] |
50
- | 10 | 19.210 | stop |
41
+ | request# | retry interval | randomized interval |
42
+ | -------- | -------------- | ------------------------------- |
43
+ | 1 | 0.5 | [0.25, 0.75] |
44
+ | 2 | 0.75 | [0.375, 1.125] |
45
+ | 3 | 1.125 | [0.5625, 1.6875] |
46
+ | 4 | 1.6875 | [0.84375, 2.53125] |
47
+ | 5 | 2.53125 | [1.265625, 3.796875] |
48
+ | 6 | 3.796875 | [1.8984375, 5.6953125] |
49
+ | 7 | 5.6953125 | [2.84765625, 8.54296875] |
50
+ | 8 | 8.54296875 | [4.271484375, 12.814453125] |
51
+ | 9 | 12.814453125 | [6.4072265625, 19.2216796875] |
52
+ | 10 | 19.2216796875 | stop |
51
53
 
52
54
  ```ruby
53
55
  require 'retriable'
@@ -66,11 +68,11 @@ end
66
68
 
67
69
  Here are the available options:
68
70
 
69
- `tries` (default: 3) - Number of attempts to make at running your code block.
71
+ `tries` (default: 3) - Number of tries to make at running your code block.
70
72
 
71
- `base_interval` (default: 0.5) - The initial interval in seconds between attempts.
73
+ `base_interval` (default: 0.5) - The initial interval in seconds between tries.
72
74
 
73
- `max_interval` (default: 60) - The maximum interval in seconds that any attempt can climb to.
75
+ `max_interval` (default: 60) - The maximum interval in seconds that any try can reach.
74
76
 
75
77
  `rand_factor` (default: 0.25) - The percent range above and below the next interval is randomized between. The calculation is calculated like this:
76
78
 
@@ -86,9 +88,9 @@ randomized_interval = retry_interval * (random value in range [1 - randomization
86
88
 
87
89
  `timeout` (default: 0) - Number of seconds to allow the code block to run before raising a Timeout::Error
88
90
 
89
- `on` (default: [StandardError]) - An `Array` of exceptions to rescue for each attempt, a `Hash` where the keys are `Exception` classes and the values can be a single `Regexp` pattern or a list of patterns, or a single `Exception` type.
91
+ `on` (default: [StandardError]) - An `Array` of exceptions to rescue for each try, a `Hash` where the keys are `Exception` classes and the values can be a single `Regexp` pattern or a list of patterns, or a single `Exception` type.
90
92
 
91
- `on_retry` - (default: nil) - Proc to call after each attempt is rescued.
93
+ `on_retry` - (default: nil) - Proc to call after each try is rescued.
92
94
 
93
95
  ### Config
94
96
 
@@ -103,7 +105,7 @@ end
103
105
 
104
106
  ### Examples
105
107
 
106
- `Retriable.retriable` accepts custom arguments. This example will only retry on a `Timeout::Error`, retry 3 times and sleep for a full second before each attempt.
108
+ `Retriable.retriable` accepts custom arguments. This example will only retry on a `Timeout::Error`, retry 3 times and sleep for a full second before each try.
107
109
 
108
110
  ```ruby
109
111
  Retriable.retriable on: Timeout::Error, tries: 3, base_interval: 1 do
@@ -131,7 +133,7 @@ Retriable.retriable on: {
131
133
  end
132
134
  ```
133
135
 
134
- You can also specify a timeout if you want the code block to only make an attempt for X amount of seconds. This timeout is per attempt.
136
+ You can also specify a timeout if you want the code block to only make an try for X amount of seconds. This timeout is per try.
135
137
 
136
138
  ```ruby
137
139
  Retriable.retriable timeout: 60 do
@@ -177,11 +179,11 @@ end
177
179
 
178
180
  ### Callbacks
179
181
 
180
- `#retriable` also provides a callback called `:on_retry` that will run after an exception is rescued. This callback provides the `exception` that was raised in the current attempt, the `try_number`, the `elapsed_time` for all attempts so far, and the time in seconds of the `next_interval`. As these are specified in a `Proc`, unnecessary variables can be left out of the parameter list.
182
+ `#retriable` also provides a callback called `:on_retry` that will run after an exception is rescued. This callback provides the `exception` that was raised in the current try, the `try_number`, the `elapsed_time` for all tries so far, and the time in seconds of the `next_interval`. As these are specified in a `Proc`, unnecessary variables can be left out of the parameter list.
181
183
 
182
184
  ```ruby
183
- do_this_on_each_retry = Proc.new do |exception, try_number, elapsed_time, next_interval|
184
- log "#{exception.class}: '#{exception.message}' - #{try_number} attempts in #{elapsed_time} seconds and #{next_interval} seconds until the next attempt."}
185
+ do_this_on_each_retry = Proc.new do |exception, try, elapsed_time, next_interval|
186
+ log "#{exception.class}: '#{exception.message}' - #{try} tries in #{elapsed_time} seconds and #{next_interval} seconds until the next try."}
185
187
  end
186
188
 
187
189
  Retriable.retriable on_retry: do_this_on_each_retry do
@@ -17,16 +17,16 @@ module Retriable
17
17
  end
18
18
 
19
19
  def retriable(
20
- tries: config.tries,
21
- base_interval: config.base_interval,
22
- max_interval: config.max_interval,
23
- rand_factor: config.rand_factor,
24
- multiplier: config.multiplier,
25
- max_elapsed_time: config.max_elapsed_time,
26
- intervals: config.intervals,
27
- timeout: config.timeout,
28
- on: config.on,
29
- on_retry: config.on_retry
20
+ tries: config.tries,
21
+ base_interval: config.base_interval,
22
+ max_interval: config.max_interval,
23
+ rand_factor: config.rand_factor,
24
+ multiplier: config.multiplier,
25
+ max_elapsed_time: config.max_elapsed_time,
26
+ intervals: config.intervals,
27
+ timeout: config.timeout,
28
+ on: config.on,
29
+ on_retry: config.on_retry
30
30
  )
31
31
 
32
32
  start_time = Time.now
@@ -46,12 +46,12 @@ module Retriable
46
46
 
47
47
  exception_list = on.kind_of?(Hash) ? on.keys : on
48
48
 
49
- intervals.each.with_index(1) do |interval, attempt|
49
+ intervals.each.with_index(1) do |interval, try|
50
50
  begin
51
51
  if timeout
52
- Timeout::timeout(timeout) { return yield(attempt) }
52
+ Timeout::timeout(timeout) { return yield(try) }
53
53
  else
54
- return yield(attempt)
54
+ return yield(try)
55
55
  end
56
56
  rescue *[*exception_list] => exception
57
57
  if on.kind_of?(Hash)
@@ -66,8 +66,8 @@ module Retriable
66
66
  raise unless message_match
67
67
  end
68
68
 
69
- on_retry.call(exception, attempt, elapsed_time.call, interval) if on_retry
70
- raise if attempt >= tries || (elapsed_time.call + interval) > max_elapsed_time
69
+ on_retry.call(exception, try, elapsed_time.call, interval) if on_retry
70
+ raise if try >= tries || (elapsed_time.call + interval) > max_elapsed_time
71
71
  sleep interval if config.sleep_disabled != true
72
72
  end
73
73
  end
@@ -19,7 +19,7 @@ module Retriable
19
19
  @max_interval = 60
20
20
  @rand_factor = 0.5
21
21
  @multiplier = 1.5
22
- @max_elapsed_time = 900 # 15 minn
22
+ @max_elapsed_time = 900 # 15 min
23
23
  @intervals = nil
24
24
  @timeout = nil
25
25
  @on = [StandardError]
@@ -7,11 +7,11 @@ module Retriable
7
7
  attr_accessor :rand_factor
8
8
 
9
9
  def initialize(
10
- tries: Retriable.config.tries,
11
- base_interval: Retriable.config.base_interval,
12
- multiplier: Retriable.config.multiplier,
13
- max_interval: Retriable.config.max_interval,
14
- rand_factor: Retriable.config.rand_factor
10
+ tries: Retriable.config.tries,
11
+ base_interval: Retriable.config.base_interval,
12
+ multiplier: Retriable.config.multiplier,
13
+ max_interval: Retriable.config.max_interval,
14
+ rand_factor: Retriable.config.rand_factor
15
15
  )
16
16
 
17
17
  @tries = tries
@@ -31,13 +31,13 @@ module Retriable
31
31
  intervals.map { |i| randomize(i) }
32
32
  end
33
33
 
34
- protected
34
+ private
35
35
  def randomize(interval)
36
36
  return interval if rand_factor == 0
37
37
  delta = rand_factor * interval * 1.0
38
- min_interval = interval - delta
39
- max_interval = interval + delta
40
- rand(min_interval..max_interval)
38
+ min = interval - delta
39
+ max = interval + delta
40
+ rand(min..max)
41
41
  end
42
42
  end
43
43
  end
@@ -1,3 +1,3 @@
1
1
  module Retriable
2
- VERSION = "2.0.0.beta5"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -1,31 +1,30 @@
1
1
  # coding: utf-8
2
- lib = File.expand_path("../lib", __FILE__)
2
+ lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require "retriable/version"
5
5
 
6
- Gem::Specification.new do |s|
7
- s.name = "retriable"
8
- s.version = Retriable::VERSION
9
- s.platform = Gem::Platform::RUBY
10
- s.authors = ["Jack Chu"]
11
- s.email = ["jack@jackchu.com"]
12
- s.homepage = %q{http://github.com/kamui/retriable}
13
- s.summary = %q{Retriable is an simple DSL to retry failed code blocks with randomized exponential backoff}
14
- s.description = %q{Retriable is an simple DSL to retry failed code blocks with randomized exponential backoff. This is especially useful when interacting external api/services or file system calls.
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "retriable"
8
+ spec.version = Retriable::VERSION
9
+ spec.authors = ["Jack Chu"]
10
+ spec.email = ["jack@jackchu.com"]
11
+ spec.summary = %q{Retriable is an simple DSL to retry failed code blocks with randomized exponential backoff}
12
+ spec.description = %q{Retriable is an simple DSL to retry failed code blocks with randomized exponential backoff. This is especially useful when interacting external api/services or file system calls.
15
13
  }
16
- s.license = "MIT"
14
+ spec.homepage = %q{http://github.com/kamui/retriable}
15
+ spec.license = "MIT"
17
16
 
18
- s.rubyforge_project = "retriable"
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
19
21
 
20
- s.files = `git ls-files`.split("\n")
21
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
23
- s.require_paths = ["lib"]
22
+ spec.required_ruby_version = '>= 2.0.0'
24
23
 
25
- s.add_development_dependency "rake"
26
- s.add_development_dependency "minitest", ">= 5.0"
27
- s.add_development_dependency "minitest-focus"
28
- s.add_development_dependency "pry"
29
- s.add_development_dependency "guard"
30
- s.add_development_dependency "guard-minitest"
24
+ spec.add_development_dependency "bundler", "~> 1.7"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+
27
+ spec.add_development_dependency "minitest", "~> 5.4"
28
+ spec.add_development_dependency "guard"
29
+ spec.add_development_dependency "guard-minitest"
31
30
  end
@@ -5,6 +5,10 @@ describe Retriable::ExponentialBackoff do
5
5
  Retriable::ExponentialBackoff
6
6
  end
7
7
 
8
+ before do
9
+ srand 0
10
+ end
11
+
8
12
  it "tries defaults to 3" do
9
13
  subject.new.tries.must_equal 3
10
14
  end
@@ -21,29 +25,71 @@ describe Retriable::ExponentialBackoff do
21
25
  subject.new.multiplier.must_equal 1.5
22
26
  end
23
27
 
24
- it "generates randomized intervals" do
25
- i = subject.new(tries: 9).intervals
26
- i[0].between?(0.25, 0.75).must_equal true
27
- i[1].between?(0.375, 1.125).must_equal true
28
- i[2].between?(0.562, 1.687).must_equal true
29
- i[3].between?(0.8435, 2.53).must_equal true
30
- i[4].between?(1.265, 3.795).must_equal true
31
- i[5].between?(1.897, 5.692).must_equal true
32
- i[6].between?(2.846, 8.538).must_equal true
33
- i[7].between?(4.269, 12.807).must_equal true
34
- i[8].between?(6.403, 19.210).must_equal true
28
+ it "generates 10 randomized intervals" do
29
+ subject.new(tries: 9).intervals.must_equal([
30
+ 0.5244067512211441,
31
+ 0.9113920238761231,
32
+ 1.2406087918999114,
33
+ 1.7632403621664823,
34
+ 2.338001204738311,
35
+ 4.350816718580626,
36
+ 5.339852157217869,
37
+ 11.889873261212443,
38
+ 18.756037881636484
39
+ ])
40
+ end
41
+
42
+ it "generates defined number of intervals" do
43
+ subject.new(tries: 5).intervals.size.must_equal 5
44
+ end
45
+
46
+ it "generates intervals with a defined base interval" do
47
+ subject.new(base_interval: 1).intervals.must_equal([
48
+ 1.0488135024422882,
49
+ 1.8227840477522461,
50
+ 2.4812175837998227
51
+ ])
52
+ end
53
+
54
+ it "generates intervals with a defined multiplier" do
55
+ subject.new(multiplier: 1).intervals.must_equal([
56
+ 0.5244067512211441,
57
+ 0.607594682584082,
58
+ 0.5513816852888495
59
+ ])
60
+ end
61
+
62
+ it "generates intervals with a defined max interval" do
63
+ subject.new(max_interval: 1.0, rand_factor: 0.0).intervals.must_equal([
64
+ 0.5,
65
+ 0.75,
66
+ 1.0
67
+ ])
68
+ end
69
+
70
+ it "generates intervals with a defined rand_factor" do
71
+ subject.new(rand_factor: 0.2).intervals.must_equal([
72
+ 0.5097627004884576,
73
+ 0.8145568095504492,
74
+ 1.1712435167599646
75
+ ])
35
76
  end
36
77
 
37
- it "generates 5 non-randomized intervals" do
78
+ it "generates 10 non-randomized intervals" do
38
79
  subject.new(
39
- tries: 5,
80
+ tries: 10,
40
81
  rand_factor: 0.0
41
82
  ).intervals.must_equal([
42
83
  0.5,
43
84
  0.75,
44
85
  1.125,
45
86
  1.6875,
46
- 2.53125
87
+ 2.53125,
88
+ 3.796875,
89
+ 5.6953125,
90
+ 8.54296875,
91
+ 12.814453125,
92
+ 19.2216796875
47
93
  ])
48
94
  end
49
95
  end
@@ -7,6 +7,10 @@ describe Retriable do
7
7
  Retriable
8
8
  end
9
9
 
10
+ before do
11
+ srand 0
12
+ end
13
+
10
14
  describe "with sleep disabled" do
11
15
  before do
12
16
  Retriable.configure do |c|
@@ -14,110 +18,128 @@ describe Retriable do
14
18
  end
15
19
  end
16
20
 
17
- it "stops at first attempt if the block does not raise an exception" do
18
- attempts = 0
21
+ it "stops at first try if the block does not raise an exception" do
22
+ tries = 0
19
23
  subject.retriable do
20
- attempts += 1
24
+ tries += 1
21
25
  end
22
26
 
23
- attempts.must_equal 1
27
+ tries.must_equal 1
24
28
  end
25
29
 
26
30
  it "raises a LocalJumpError if #retriable is not given a block" do
27
31
  -> do
28
- subject.retriable on: EOFError
32
+ subject.retriable on: StandardError
29
33
  end.must_raise LocalJumpError
30
34
 
31
35
  -> do
32
- subject.retriable on: EOFError, timeout: 2
36
+ subject.retriable on: StandardError, timeout: 2
33
37
  end.must_raise LocalJumpError
34
38
  end
35
39
 
36
- describe "#retriable block of code raising EOFError with no arguments" do
37
- before do
38
- @attempts = 0
40
+ it "makes 3 tries when retrying block of code raising StandardError with no arguments" do
41
+ tries = 0
39
42
 
43
+ -> do
40
44
  subject.retriable do
41
- @attempts += 1
42
- raise EOFError.new if @attempts < 3
45
+ tries += 1
46
+ raise StandardError.new
43
47
  end
44
- end
48
+ end.must_raise StandardError
45
49
 
46
- it "uses exponential backoff" do
47
- @attempts.must_equal 3
48
- end
50
+ tries.must_equal 3
51
+ end
52
+
53
+ it "makes only 1 try when exception raised is not ancestor of StandardError" do
54
+ tries = 0
55
+
56
+ -> do
57
+ subject.retriable do
58
+ tries += 1
59
+ raise TestError.new
60
+ end
61
+ end.must_raise TestError
62
+
63
+ tries.must_equal 1
49
64
  end
50
65
 
51
- it "#retriable on custom exception and re-raises the exception" do
66
+ it "#retriable with custom exception tries 3 times and re-raises the exception" do
67
+ tries = 0
52
68
  -> do
53
69
  subject.retriable on: TestError do
70
+ tries += 1
54
71
  raise TestError.new
55
72
  end
56
73
  end.must_raise TestError
74
+
75
+ tries.must_equal 3
57
76
  end
58
77
 
59
78
  it "#retriable tries 10 times" do
60
- attempts = 0
79
+ tries = 0
61
80
 
62
- subject.retriable(
63
- tries: 10
64
- ) do
65
- attempts += 1
66
- raise EOFError.new if attempts < 10
67
- end
81
+ -> do
82
+ subject.retriable(
83
+ tries: 10
84
+ ) do
85
+ tries += 1
86
+ raise StandardError.new
87
+ end
88
+ end.must_raise StandardError
68
89
 
69
- attempts.must_equal 10
90
+ tries.must_equal 10
70
91
  end
71
92
 
72
93
  it "#retriable will timeout after 1 second" do
73
94
  -> do
74
95
  subject.retriable timeout: 1 do
75
- sleep 2
96
+ sleep 1.1
76
97
  end
77
98
  end.must_raise Timeout::Error
78
99
  end
79
100
 
80
- it "applies a randomized exponential backoff to each attempt" do
81
- @attempts = 0
82
- @time_table = {}
101
+ it "applies a randomized exponential backoff to each try" do
102
+ @tries = 0
103
+ @time_table = []
83
104
 
84
- handler = ->(exception, attempt, elapsed_time, next_interval) do
105
+ handler = ->(exception, try, elapsed_time, next_interval) do
85
106
  exception.class.must_equal ArgumentError
86
- @time_table[attempt] = next_interval
107
+ @time_table << next_interval
87
108
  end
88
109
 
89
110
  -> do
90
111
  Retriable.retriable(
91
112
  on: [EOFError, ArgumentError],
92
113
  on_retry: handler,
93
- rand_factor: 0.0,
94
114
  tries: 9
95
115
  ) do
96
- @attempts += 1
116
+ @tries += 1
97
117
  raise ArgumentError.new
98
118
  end
99
119
  end.must_raise ArgumentError
100
120
 
101
- @time_table[1].between?(0.25, 0.75).must_equal true
102
- @time_table[2].between?(0.375, 1.125).must_equal true
103
- @time_table[3].between?(0.562, 1.687).must_equal true
104
- @time_table[4].between?(0.8435, 2.53).must_equal true
105
- @time_table[5].between?(1.265, 3.795).must_equal true
106
- @time_table[6].between?(1.897, 5.692).must_equal true
107
- @time_table[7].between?(2.846, 8.538).must_equal true
108
- @time_table[8].between?(4.269, 12.807).must_equal true
109
- @time_table[9].between?(6.403, 19.210).must_equal true
121
+ @time_table.must_equal([
122
+ 0.5244067512211441,
123
+ 0.9113920238761231,
124
+ 1.2406087918999114,
125
+ 1.7632403621664823,
126
+ 2.338001204738311,
127
+ 4.350816718580626,
128
+ 5.339852157217869,
129
+ 11.889873261212443,
130
+ 18.756037881636484
131
+ ])
110
132
  end
111
133
 
112
134
  describe "retries with an on_#retriable handler, 6 max retries, and a 0.0 rand_factor" do
113
135
  before do
114
136
  tries = 6
115
- @attempts = 0
137
+ @tries = 0
116
138
  @time_table = {}
117
139
 
118
- handler = ->(exception, attempt, elapsed_time, next_interval) do
140
+ handler = ->(exception, try, elapsed_time, next_interval) do
119
141
  exception.class.must_equal ArgumentError
120
- @time_table[attempt] = next_interval
142
+ @time_table[try] = next_interval
121
143
  end
122
144
 
123
145
  Retriable.retriable(
@@ -126,16 +148,16 @@ describe Retriable do
126
148
  rand_factor: 0.0,
127
149
  tries: tries
128
150
  ) do
129
- @attempts += 1
130
- raise ArgumentError.new if @attempts < tries
151
+ @tries += 1
152
+ raise ArgumentError.new if @tries < tries
131
153
  end
132
154
  end
133
155
 
134
- it "makes 6 attempts" do
135
- @attempts.must_equal 6
156
+ it "makes 6 tries" do
157
+ @tries.must_equal 6
136
158
  end
137
159
 
138
- it "applies a non-randomized exponential backoff to each attempt" do
160
+ it "applies a non-randomized exponential backoff to each try" do
139
161
  @time_table.must_equal({
140
162
  1 => 0.5,
141
163
  2 => 0.75,
@@ -147,24 +169,25 @@ describe Retriable do
147
169
  end
148
170
 
149
171
  it "#retriable has a max interval of 1.5 seconds" do
150
- tries = 6
151
- attempts = 0
172
+ tries = 0
152
173
  time_table = {}
153
174
 
154
- handler = ->(exception, attempt, elapsed_time, next_interval) do
155
- time_table[attempt] = next_interval
175
+ handler = ->(exception, try, elapsed_time, next_interval) do
176
+ time_table[try] = next_interval
156
177
  end
157
178
 
158
- subject.retriable(
159
- on: EOFError,
160
- on_retry: handler,
161
- rand_factor: 0.0,
162
- tries: tries,
163
- max_interval: 1.5
164
- ) do
165
- attempts += 1
166
- raise EOFError.new if attempts < tries
167
- end
179
+ -> do
180
+ subject.retriable(
181
+ on: StandardError,
182
+ on_retry: handler,
183
+ rand_factor: 0.0,
184
+ tries: 5,
185
+ max_interval: 1.5
186
+ ) do
187
+ tries += 1
188
+ raise StandardError.new
189
+ end
190
+ end.must_raise StandardError
168
191
 
169
192
  time_table.must_equal({
170
193
  1 => 0.5,
@@ -175,7 +198,7 @@ describe Retriable do
175
198
  })
176
199
  end
177
200
 
178
- it "#retriable with defined intervals" do
201
+ it "#retriable with custom defined intervals" do
179
202
  intervals = [
180
203
  0.5,
181
204
  0.75,
@@ -185,19 +208,18 @@ describe Retriable do
185
208
  ]
186
209
  time_table = {}
187
210
 
188
- handler = ->(exception, attempt, elapsed_time, next_interval) do
189
- time_table[attempt] = next_interval
211
+ handler = ->(exception, try, elapsed_time, next_interval) do
212
+ time_table[try] = next_interval
190
213
  end
191
214
 
192
215
  -> do
193
216
  subject.retriable(
194
- on: EOFError,
195
217
  on_retry: handler,
196
218
  intervals: intervals
197
219
  ) do
198
- raise EOFError.new
220
+ raise StandardError.new
199
221
  end
200
- end.must_raise EOFError
222
+ end.must_raise StandardError
201
223
 
202
224
  time_table.must_equal({
203
225
  1 => 0.5,
@@ -219,22 +241,22 @@ describe Retriable do
219
241
  end
220
242
 
221
243
  it "#retriable with a hash exception list where the values are exception message patterns" do
222
- attempts = 0
223
- tries = []
224
- handler = ->(exception, attempt, elapsed_time, next_interval) do
225
- tries[attempt] = exception
244
+ tries = 0
245
+ exceptions = []
246
+ handler = ->(exception, try, elapsed_time, next_interval) do
247
+ exceptions[try] = exception
226
248
  end
227
249
 
228
250
  e = -> do
229
- subject.retriable tries: 4, on: { EOFError => nil, TestError => [/foo/, /bar/] }, on_retry: handler do
230
- attempts += 1
231
- case attempts
251
+ subject.retriable tries: 4, on: { StandardError => nil, TestError => [/foo/, /bar/] }, on_retry: handler do
252
+ tries += 1
253
+ case tries
232
254
  when 1
233
255
  raise TestError.new('foo')
234
256
  when 2
235
257
  raise TestError.new('bar')
236
258
  when 3
237
- raise EOFError.new
259
+ raise StandardError.new
238
260
  else
239
261
  raise TestError.new('crash')
240
262
  end
@@ -242,11 +264,11 @@ describe Retriable do
242
264
  end.must_raise TestError
243
265
 
244
266
  e.message.must_equal "crash"
245
- tries[1].class.must_equal TestError
246
- tries[1].message.must_equal "foo"
247
- tries[2].class.must_equal TestError
248
- tries[2].message.must_equal "bar"
249
- tries[3].class.must_equal EOFError
267
+ exceptions[1].class.must_equal TestError
268
+ exceptions[1].message.must_equal "foo"
269
+ exceptions[2].class.must_equal TestError
270
+ exceptions[2].message.must_equal "bar"
271
+ exceptions[3].class.must_equal StandardError
250
272
  end
251
273
 
252
274
  it "#retriable can be called in the global scope" do
@@ -258,12 +280,16 @@ describe Retriable do
258
280
 
259
281
  require_relative "../lib/retriable/core_ext/kernel"
260
282
 
261
- attempts = 0
262
- retriable do
263
- attempts += 1
264
- raise EOFError.new if attempts < 3
265
- end
266
- attempts.must_equal 3
283
+ tries = 0
284
+
285
+ -> do
286
+ retriable do
287
+ tries += 1
288
+ raise StandardError.new
289
+ end
290
+ end.must_raise StandardError
291
+
292
+ tries.must_equal 3
267
293
  end
268
294
  end
269
295
 
@@ -274,11 +300,11 @@ describe Retriable do
274
300
 
275
301
  subject.config.sleep_disabled.must_equal false
276
302
 
277
- attempts = 0
303
+ tries = 0
278
304
  time_table = {}
279
305
 
280
- handler = ->(exception, attempt, elapsed_time, next_interval) do
281
- time_table[attempt] = elapsed_time
306
+ handler = ->(exception, try, elapsed_time, next_interval) do
307
+ time_table[try] = elapsed_time
282
308
  end
283
309
 
284
310
  -> do
@@ -289,11 +315,11 @@ describe Retriable do
289
315
  max_elapsed_time: 2.0,
290
316
  on_retry: handler
291
317
  ) do
292
- attempts += 1
318
+ tries += 1
293
319
  raise EOFError.new
294
320
  end
295
321
  end.must_raise EOFError
296
322
 
297
- attempts.must_equal 2
323
+ tries.must_equal 2
298
324
  end
299
325
  end
@@ -1,5 +1,21 @@
1
+ require "codeclimate-test-reporter"
2
+ require "simplecov"
3
+
4
+ CodeClimate::TestReporter.configure do |config|
5
+ config.logger.level = Logger::WARN
6
+ end
7
+
8
+ SimpleCov.start do
9
+ formatter SimpleCov::Formatter::MultiFormatter[
10
+ SimpleCov::Formatter::HTMLFormatter,
11
+ CodeClimate::TestReporter::Formatter
12
+ ]
13
+ add_filter 'spec/'
14
+ end
15
+
1
16
  require "minitest/autorun"
2
17
  require "minitest/focus"
18
+ require "awesome_print"
3
19
  require "pry"
4
20
 
5
21
  require_relative "../lib/retriable"
@@ -6,8 +6,8 @@ build:
6
6
  # http://devcenter.wercker.com/articles/languages/ruby.html
7
7
  steps:
8
8
  # Uncomment this to force RVM to use a specific Ruby version
9
- # - rvm-use:
10
- # version: 2.1.0
9
+ - rvm-use:
10
+ version: 2.1.5
11
11
 
12
12
  # A step that executes `bundle install` command
13
13
  - bundle-install
metadata CHANGED
@@ -1,71 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: retriable
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.beta5
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jack Chu
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-09 00:00:00.000000000 Z
11
+ date: 2015-01-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rake
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: minitest
14
+ name: bundler
29
15
  requirement: !ruby/object:Gem::Requirement
30
16
  requirements:
31
- - - ">="
17
+ - - "~>"
32
18
  - !ruby/object:Gem::Version
33
- version: '5.0'
19
+ version: '1.7'
34
20
  type: :development
35
21
  prerelease: false
36
22
  version_requirements: !ruby/object:Gem::Requirement
37
23
  requirements:
38
- - - ">="
24
+ - - "~>"
39
25
  - !ruby/object:Gem::Version
40
- version: '5.0'
26
+ version: '1.7'
41
27
  - !ruby/object:Gem::Dependency
42
- name: minitest-focus
28
+ name: rake
43
29
  requirement: !ruby/object:Gem::Requirement
44
30
  requirements:
45
- - - ">="
31
+ - - "~>"
46
32
  - !ruby/object:Gem::Version
47
- version: '0'
33
+ version: '10.0'
48
34
  type: :development
49
35
  prerelease: false
50
36
  version_requirements: !ruby/object:Gem::Requirement
51
37
  requirements:
52
- - - ">="
38
+ - - "~>"
53
39
  - !ruby/object:Gem::Version
54
- version: '0'
40
+ version: '10.0'
55
41
  - !ruby/object:Gem::Dependency
56
- name: pry
42
+ name: minitest
57
43
  requirement: !ruby/object:Gem::Requirement
58
44
  requirements:
59
- - - ">="
45
+ - - "~>"
60
46
  - !ruby/object:Gem::Version
61
- version: '0'
47
+ version: '5.4'
62
48
  type: :development
63
49
  prerelease: false
64
50
  version_requirements: !ruby/object:Gem::Requirement
65
51
  requirements:
66
- - - ">="
52
+ - - "~>"
67
53
  - !ruby/object:Gem::Version
68
- version: '0'
54
+ version: '5.4'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: guard
71
57
  requirement: !ruby/object:Gem::Requirement
@@ -133,15 +119,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
133
119
  requirements:
134
120
  - - ">="
135
121
  - !ruby/object:Gem::Version
136
- version: '0'
122
+ version: 2.0.0
137
123
  required_rubygems_version: !ruby/object:Gem::Requirement
138
124
  requirements:
139
- - - ">"
125
+ - - ">="
140
126
  - !ruby/object:Gem::Version
141
- version: 1.3.1
127
+ version: '0'
142
128
  requirements: []
143
- rubyforge_project: retriable
144
- rubygems_version: 2.2.2
129
+ rubyforge_project:
130
+ rubygems_version: 2.4.5
145
131
  signing_key:
146
132
  specification_version: 4
147
133
  summary: Retriable is an simple DSL to retry failed code blocks with randomized exponential