retryable 1.3.6 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +4 -0
- data/README.md +10 -10
- data/lib/retryable.rb +4 -4
- data/lib/retryable/version.rb +3 -3
- data/spec/lib/config_spec.rb +4 -4
- data/spec/lib/retryable_spec.rb +44 -44
- data/spec/spec_helper.rb +2 -4
- metadata +13 -11
- checksums.yaml +0 -7
- data/spec/lib/version_spec.rb +0 -7
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -24,7 +24,7 @@ Open an URL, retry up to two times when an `OpenURI::HTTPError` occurs.
|
|
24
24
|
``` ruby
|
25
25
|
require "open-uri"
|
26
26
|
|
27
|
-
retryable(:tries => 3, :on => OpenURI::HTTPError) do
|
27
|
+
Retryable.retryable(:tries => 3, :on => OpenURI::HTTPError) do
|
28
28
|
xml = open("http://example.com/test.xml").read
|
29
29
|
end
|
30
30
|
```
|
@@ -33,7 +33,7 @@ Do _something_, retry up to four times for either `ArgumentError` or
|
|
33
33
|
`TimeoutError` exceptions.
|
34
34
|
|
35
35
|
``` ruby
|
36
|
-
retryable(:tries => 5, :on => [ArgumentError, TimeoutError]) do
|
36
|
+
Retryable.retryable(:tries => 5, :on => [ArgumentError, TimeoutError]) do
|
37
37
|
# some crazy code
|
38
38
|
end
|
39
39
|
```
|
@@ -49,7 +49,7 @@ ensure_cb = Proc.new do |retries|
|
|
49
49
|
f.close
|
50
50
|
end
|
51
51
|
|
52
|
-
retryable(:ensure => ensure_cb) do
|
52
|
+
Retryable.retryable(:ensure => ensure_cb) do
|
53
53
|
# process file
|
54
54
|
end
|
55
55
|
```
|
@@ -63,9 +63,9 @@ Sleeping
|
|
63
63
|
By default Retryable waits for one second between retries. You can change this and even provide your own exponential backoff scheme.
|
64
64
|
|
65
65
|
```
|
66
|
-
retryable(:sleep => 0) { }
|
67
|
-
retryable(:sleep => 10) { }
|
68
|
-
retryable(:sleep => lambda { |n| 4**n }) { } # sleep 1, 4, 16, etc. each try
|
66
|
+
Retryable.retryable(:sleep => 0) { } # don't pause at all between retries
|
67
|
+
Retryable.retryable(:sleep => 10) { } # sleep ten seconds between retries
|
68
|
+
Retryable.retryable(:sleep => lambda { |n| 4**n }) { } # sleep 1, 4, 16, etc. each try
|
69
69
|
```
|
70
70
|
|
71
71
|
Matching error messages
|
@@ -73,7 +73,7 @@ Matching error messages
|
|
73
73
|
You can also retry based on the exception message:
|
74
74
|
|
75
75
|
```
|
76
|
-
retryable(:matching => /IO timeout/) do |retries, exception|
|
76
|
+
Retryable.retryable(:matching => /IO timeout/) do |retries, exception|
|
77
77
|
raise "yo, IO timeout!" if retries == 0
|
78
78
|
end
|
79
79
|
```
|
@@ -83,7 +83,7 @@ Block Parameters
|
|
83
83
|
Your block is called with two optional parameters: the number of tries until now, and the most recent exception.
|
84
84
|
|
85
85
|
```
|
86
|
-
retryable do |retries, exception|
|
86
|
+
Retryable.retryable do |retries, exception|
|
87
87
|
puts "try #{retries} failed with exception: #{exception}" if retries > 0
|
88
88
|
pick_up_soap
|
89
89
|
end
|
@@ -98,7 +98,7 @@ exception_cb = Proc.new do |exception|
|
|
98
98
|
ExceptionNotifier.notify_exception(exception, :data => {:message => "it failed"})
|
99
99
|
end
|
100
100
|
|
101
|
-
retryable(:exception_cb => exception_cb) do
|
101
|
+
Retryable.retryable(:exception_cb => exception_cb) do
|
102
102
|
# perform risky operation
|
103
103
|
end
|
104
104
|
```
|
@@ -126,7 +126,7 @@ versions:
|
|
126
126
|
* Ruby 1.9.2
|
127
127
|
* Ruby 1.9.3
|
128
128
|
* Ruby 2.0.0
|
129
|
-
* Ruby 2.1.
|
129
|
+
* Ruby 2.1.2
|
130
130
|
|
131
131
|
If something doesn't work on one of these versions, it's a bug.
|
132
132
|
|
data/lib/retryable.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'retryable/version'
|
2
2
|
require 'retryable/config'
|
3
3
|
|
4
|
-
module
|
5
|
-
def retryable(options = {}, &block)
|
4
|
+
module Retryable
|
5
|
+
def self.retryable(options = {}, &block)
|
6
6
|
opts = {:tries => 2, :sleep => 1, :on => StandardError, :matching => /.*/, :ensure => Proc.new {}, :exception_cb => Proc.new {}}
|
7
7
|
check_for_invalid_options(options, opts)
|
8
8
|
opts.merge!(options)
|
@@ -22,7 +22,7 @@ module Kernel
|
|
22
22
|
|
23
23
|
# Interrupt Exception could be raised while sleeping
|
24
24
|
begin
|
25
|
-
sleep opts[:sleep].respond_to?(:call) ? opts[:sleep].call(retries) : opts[:sleep]
|
25
|
+
Kernel.sleep opts[:sleep].respond_to?(:call) ? opts[:sleep].call(retries) : opts[:sleep]
|
26
26
|
rescue *on_exception
|
27
27
|
end
|
28
28
|
|
@@ -37,7 +37,7 @@ module Kernel
|
|
37
37
|
|
38
38
|
private
|
39
39
|
|
40
|
-
def check_for_invalid_options(custom_options, default_options)
|
40
|
+
def self.check_for_invalid_options(custom_options, default_options)
|
41
41
|
invalid_options = default_options.merge(custom_options).keys - default_options.keys
|
42
42
|
|
43
43
|
raise ArgumentError.new("[Retryable] Invalid options: #{invalid_options.join(", ")}") unless invalid_options.empty?
|
data/lib/retryable/version.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
module Retryable
|
2
2
|
class Version
|
3
|
-
MAJOR =
|
4
|
-
MINOR =
|
5
|
-
PATCH =
|
3
|
+
MAJOR = 2 unless defined? Retryable::Version::MAJOR
|
4
|
+
MINOR = 0 unless defined? Retryable::Version::MINOR
|
5
|
+
PATCH = 0 unless defined? Retryable::Version::PATCH
|
6
6
|
|
7
7
|
class << self
|
8
8
|
|
data/spec/lib/config_spec.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Retryable do
|
3
|
+
RSpec.describe Retryable do
|
4
4
|
it 'is enabled by default' do
|
5
|
-
Retryable.
|
5
|
+
expect(Retryable).to be_enabled
|
6
6
|
end
|
7
7
|
|
8
8
|
it 'could be disabled' do
|
9
9
|
Retryable.disable
|
10
|
-
Retryable.
|
10
|
+
expect(Retryable).not_to be_enabled
|
11
11
|
end
|
12
12
|
|
13
13
|
context 'when disabled' do
|
@@ -17,7 +17,7 @@ describe Retryable do
|
|
17
17
|
|
18
18
|
it 'could be re-enabled' do
|
19
19
|
Retryable.enable
|
20
|
-
Retryable.
|
20
|
+
expect(Retryable).to be_enabled
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
data/spec/lib/retryable_spec.rb
CHANGED
@@ -1,118 +1,118 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe '
|
3
|
+
RSpec.describe 'Retryable.retryable' do
|
4
4
|
before(:each) do
|
5
5
|
Retryable.enable
|
6
6
|
@attempt = 0
|
7
7
|
end
|
8
8
|
|
9
9
|
it 'catch StandardError only by default' do
|
10
|
-
|
10
|
+
expect do
|
11
11
|
count_retryable(:tries => 2) { |tries, ex| raise Exception if tries < 1 }
|
12
|
-
end.
|
13
|
-
@try_count.
|
12
|
+
end.to raise_error Exception
|
13
|
+
expect(@try_count).to eq(1)
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'retries on default exception' do
|
17
|
-
Kernel.
|
17
|
+
expect(Kernel).to receive(:sleep).once.with(1)
|
18
18
|
|
19
19
|
count_retryable(:tries => 2) { |tries, ex| raise StandardError if tries < 1 }
|
20
|
-
@try_count.
|
20
|
+
expect(@try_count).to eq(2)
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'does not retry if disabled' do
|
24
24
|
Retryable.disable
|
25
25
|
|
26
|
-
|
26
|
+
expect do
|
27
27
|
count_retryable(:tries => 2) { raise }
|
28
|
-
end.
|
29
|
-
@try_count.
|
28
|
+
end.to raise_error RuntimeError
|
29
|
+
expect(@try_count).to eq(1)
|
30
30
|
end
|
31
31
|
|
32
32
|
it 'executes *ensure* clause' do
|
33
33
|
ensure_cb = Proc.new do |retries|
|
34
|
-
retries.
|
34
|
+
expect(retries).to eq(0)
|
35
35
|
end
|
36
36
|
|
37
|
-
|
37
|
+
Retryable.retryable(:ensure => ensure_cb) { }
|
38
38
|
end
|
39
39
|
|
40
40
|
it 'passes retry count and exception on retry' do
|
41
|
-
Kernel.
|
41
|
+
expect(Kernel).to receive(:sleep).once.with(1)
|
42
42
|
|
43
43
|
count_retryable(:tries => 2) do |tries, ex|
|
44
|
-
ex.class.
|
44
|
+
expect(ex.class).to eq(StandardError) if tries > 0
|
45
45
|
raise StandardError if tries < 1
|
46
46
|
end
|
47
|
-
@try_count.
|
47
|
+
expect(@try_count).to eq(2)
|
48
48
|
end
|
49
49
|
|
50
50
|
it 'makes another try if exception is covered by :on' do
|
51
|
-
Kernel.
|
51
|
+
allow(Kernel).to receive(:sleep)
|
52
52
|
count_retryable(:on => [StandardError, ArgumentError, RuntimeError] ) { |tries, ex| raise ArgumentError if tries < 1 }
|
53
|
-
@try_count.
|
53
|
+
expect(@try_count).to eq(2)
|
54
54
|
end
|
55
55
|
|
56
56
|
it 'does not try on unexpected exception' do
|
57
|
-
Kernel.
|
58
|
-
|
57
|
+
allow(Kernel).to receive(:sleep)
|
58
|
+
expect do
|
59
59
|
count_retryable(:on => RuntimeError ) { |tries, ex| raise StandardError if tries < 1 }
|
60
|
-
end.
|
61
|
-
@try_count.
|
60
|
+
end.to raise_error StandardError
|
61
|
+
expect(@try_count).to eq(1)
|
62
62
|
end
|
63
63
|
|
64
64
|
it 'retries three times' do
|
65
|
-
Kernel.
|
65
|
+
allow(Kernel).to receive(:sleep)
|
66
66
|
count_retryable(:tries => 3) { |tries, ex| raise StandardError if tries < 2 }
|
67
|
-
@try_count.
|
67
|
+
expect(@try_count).to eq(3)
|
68
68
|
end
|
69
69
|
|
70
70
|
it 'retries on default exception' do
|
71
|
-
Kernel.
|
71
|
+
expect(Kernel).to receive(:sleep).once.with(1)
|
72
72
|
|
73
73
|
count_retryable(:tries => 2) { |tries, ex| raise StandardError if tries < 1 }
|
74
|
-
@try_count.
|
74
|
+
expect(@try_count).to eq(2)
|
75
75
|
end
|
76
76
|
|
77
77
|
it 'executes exponential backoff scheme for :sleep option' do
|
78
|
-
[1, 4, 16, 64].each { |i| Kernel.
|
79
|
-
|
80
|
-
|
81
|
-
end.
|
78
|
+
[1, 4, 16, 64].each { |i| expect(Kernel).to receive(:sleep).once.ordered.with(i) }
|
79
|
+
expect do
|
80
|
+
Retryable.retryable(:tries => 5, :sleep => lambda { |n| 4**n }) { raise RangeError }
|
81
|
+
end.to raise_error RangeError
|
82
82
|
end
|
83
83
|
|
84
84
|
it 'does not retry any exception if :on is empty list' do
|
85
|
-
|
85
|
+
expect do
|
86
86
|
count_retryable(:on => []) { raise }
|
87
|
-
end.
|
88
|
-
@try_count.
|
87
|
+
end.to raise_error RuntimeError
|
88
|
+
expect(@try_count).to eq(1)
|
89
89
|
end
|
90
90
|
|
91
91
|
it 'catches an exception that matches the regex' do
|
92
|
-
Kernel.
|
92
|
+
expect(Kernel).to receive(:sleep).once.with(1)
|
93
93
|
count_retryable(:matching => /IO timeout/) { |c,e| raise "yo, IO timeout!" if c == 0 }
|
94
|
-
@try_count.
|
94
|
+
expect(@try_count).to eq(2)
|
95
95
|
end
|
96
96
|
|
97
97
|
it 'does not catch an exception that does not match the regex' do
|
98
|
-
|
99
|
-
|
98
|
+
expect(Kernel).not_to receive(:sleep)
|
99
|
+
expect do
|
100
100
|
count_retryable(:matching => /TimeError/) { raise "yo, IO timeout!" }
|
101
|
-
end.
|
102
|
-
@try_count.
|
101
|
+
end.to raise_error RuntimeError
|
102
|
+
expect(@try_count).to eq(1)
|
103
103
|
end
|
104
104
|
|
105
105
|
it 'does not allow invalid options' do
|
106
|
-
|
107
|
-
retryable(:bad_option => 2) { raise "this is bad" }
|
108
|
-
end.
|
106
|
+
expect do
|
107
|
+
Retryable.retryable(:bad_option => 2) { raise "this is bad" }
|
108
|
+
end.to raise_error ArgumentError, '[Retryable] Invalid options: bad_option'
|
109
109
|
end
|
110
110
|
|
111
111
|
it 'accepts a callback to run after an exception is rescued' do
|
112
|
-
|
113
|
-
retryable(:sleep => 0, :exception_cb => Proc.new {|e| @raised = e.to_s }) {|tries, ex| raise StandardError.new("this is fun!") if tries < 1 }
|
114
|
-
end.
|
112
|
+
expect do
|
113
|
+
Retryable.retryable(:sleep => 0, :exception_cb => Proc.new {|e| @raised = e.to_s }) {|tries, ex| raise StandardError.new("this is fun!") if tries < 1 }
|
114
|
+
end.not_to raise_error
|
115
115
|
|
116
|
-
@raised.
|
116
|
+
expect(@raised).to eq("this is fun!")
|
117
117
|
end
|
118
118
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,13 +2,11 @@ require File.dirname(__FILE__) + '/../lib/retryable'
|
|
2
2
|
require 'rspec'
|
3
3
|
|
4
4
|
RSpec.configure do |config|
|
5
|
-
|
6
|
-
# methods or matchers
|
7
|
-
require 'rspec/expectations'
|
5
|
+
config.disable_monkey_patching!
|
8
6
|
|
9
7
|
def count_retryable(*opts)
|
10
8
|
@try_count = 0
|
11
|
-
return
|
9
|
+
return Retryable.retryable(*opts) do |*args|
|
12
10
|
@try_count += 1
|
13
11
|
yield *args
|
14
12
|
end
|
metadata
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: retryable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
|
+
prerelease:
|
5
6
|
platform: ruby
|
6
7
|
authors:
|
7
8
|
- Nikita Fedyashev
|
@@ -10,11 +11,12 @@ authors:
|
|
10
11
|
autorequire:
|
11
12
|
bindir: bin
|
12
13
|
cert_chain: []
|
13
|
-
date: 2014-
|
14
|
+
date: 2014-12-03 00:00:00.000000000 Z
|
14
15
|
dependencies:
|
15
16
|
- !ruby/object:Gem::Dependency
|
16
17
|
name: bundler
|
17
18
|
requirement: !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
18
20
|
requirements:
|
19
21
|
- - ~>
|
20
22
|
- !ruby/object:Gem::Version
|
@@ -22,6 +24,7 @@ dependencies:
|
|
22
24
|
type: :development
|
23
25
|
prerelease: false
|
24
26
|
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
none: false
|
25
28
|
requirements:
|
26
29
|
- - ~>
|
27
30
|
- !ruby/object:Gem::Version
|
@@ -36,40 +39,39 @@ files:
|
|
36
39
|
- LICENSE.md
|
37
40
|
- README.md
|
38
41
|
- Rakefile
|
39
|
-
-
|
42
|
+
- retryable.gemspec
|
40
43
|
- lib/retryable/config.rb
|
41
44
|
- lib/retryable/version.rb
|
42
|
-
- retryable.
|
45
|
+
- lib/retryable.rb
|
43
46
|
- spec/lib/config_spec.rb
|
44
47
|
- spec/lib/retryable_spec.rb
|
45
|
-
- spec/lib/version_spec.rb
|
46
48
|
- spec/spec_helper.rb
|
47
49
|
homepage: http://github.com/nfedyashev/retryable
|
48
50
|
licenses: []
|
49
|
-
metadata: {}
|
50
51
|
post_install_message:
|
51
52
|
rdoc_options: []
|
52
53
|
require_paths:
|
53
54
|
- lib
|
54
55
|
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
55
57
|
requirements:
|
56
|
-
- - '>='
|
58
|
+
- - ! '>='
|
57
59
|
- !ruby/object:Gem::Version
|
58
60
|
version: '0'
|
59
61
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
60
63
|
requirements:
|
61
|
-
- - '>='
|
64
|
+
- - ! '>='
|
62
65
|
- !ruby/object:Gem::Version
|
63
66
|
version: 1.3.6
|
64
67
|
requirements: []
|
65
68
|
rubyforge_project:
|
66
|
-
rubygems_version:
|
69
|
+
rubygems_version: 1.8.23
|
67
70
|
signing_key:
|
68
|
-
specification_version:
|
71
|
+
specification_version: 3
|
69
72
|
summary: Kernel#retryable, allow for retrying of code blocks.
|
70
73
|
test_files:
|
71
74
|
- spec/lib/config_spec.rb
|
72
75
|
- spec/lib/retryable_spec.rb
|
73
|
-
- spec/lib/version_spec.rb
|
74
76
|
- spec/spec_helper.rb
|
75
77
|
has_rdoc:
|
checksums.yaml
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
---
|
2
|
-
SHA1:
|
3
|
-
metadata.gz: c055a594c5bd9ebeb455b8185e027ea0d2ce259c
|
4
|
-
data.tar.gz: 2cbbb09e5958d1f211810dbc762bfd962a102eaf
|
5
|
-
SHA512:
|
6
|
-
metadata.gz: c1f320b8298024f48f24677e4538d6da832287a7f00269da165b41454a242e2777bc7978c84916148afaa50bf63936090ae315da8e151b9fe3d6ae60d7085229
|
7
|
-
data.tar.gz: f75b5c6bc559c0b5841a95d74914ac16fe24e399365aed35a3b9c7500c1c08d9a636def180e12f0773558252f1ddc371fcf5496f47e16301f300e00ebef904f2
|