attempt_this 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a25ae3dbdf326fbbfd6ac7f4f87576495d4aa2ff
4
+ data.tar.gz: 570ce5129322b14d1b0c61a463daeb6b3c335962
5
+ SHA512:
6
+ metadata.gz: e97953cc5b47eedbe6f6398ec1e1ad528aadf2cd36829dc8e5533c80846b0344fd1f5efc95a7bf4fc8481b866175f1a732dd1a4de88d57ddfa66f44f2cc96f68
7
+ data.tar.gz: 135cd4ad6336d9c63b9a6d58c3858706dd5445d73cd882e9e94ea6ea0dbbbb9db40df5a1dabfd66fea82b480c8ec9ca565fefcfd8bd4b7506601917879851c98
@@ -0,0 +1,112 @@
1
+ require_relative 'binary_backoff_policy.rb'
2
+ require_relative 'exception_type_filter.rb'
3
+
4
+ module AttemptThis
5
+ # Retry policy implementation.
6
+ # This class is internal and is not supposed to be used outside of the module.
7
+ class AttemptObject
8
+ # Initializes object with enumerator.
9
+ def initialize(enumerator)
10
+ @enumerator = enumerator
11
+ end
12
+
13
+ # Executes the code block.
14
+ def attempt(block)
15
+ if (block)
16
+ last_exception = nil
17
+ first_time = true
18
+
19
+ @delay_policy = ->{} unless @delay_policy
20
+ @reset_method = ->{} unless @reset_method
21
+ @exception_filter = ExceptionTypeFilter.new([StandardError]) unless @exception_filter
22
+
23
+ @enumerator.each do
24
+ @delay_policy.call unless first_time
25
+ last_exception = nil
26
+ begin
27
+ block.call
28
+ break
29
+ rescue => ex
30
+ raise unless @exception_filter.include?(ex)
31
+ last_exception = ex
32
+ @reset_method.call
33
+ end
34
+ first_time = false
35
+ end
36
+
37
+ # Re-raise the last exception
38
+ if (last_exception)
39
+ if (@default_method)
40
+ @default_method.call
41
+ else
42
+ raise last_exception
43
+ end
44
+ end
45
+ end
46
+
47
+ # Return self to allow chaining calls.
48
+ self
49
+ end
50
+
51
+ # Specifies delay in seconds between failed attempts.
52
+ def with_delay(delay, &block)
53
+ # Delay should be either an integer or a range of integers.
54
+ if (delay.is_a?(Numeric))
55
+ raise(ArgumentError, "Delay should be a non-negative number; got #{delay}!") unless delay >= 0
56
+ delay = delay..delay
57
+ elsif delay.is_a?(Range)
58
+ raise(ArgumentError, "Range members should be numbers; got #{delay}!") unless delay.first.is_a?(Numeric) && delay.last.is_a?(Numeric)
59
+ raise(ArgumentError, "Range members should be non-negative; got #{delay}!") unless delay.first >= 0 && delay.last >= 0
60
+ raise(ArgumentError, "Range's end should be greater than or equal to range's start; got #{delay}!") unless delay.first <= delay.last
61
+ else
62
+ raise(ArgumentError, "Delay should be either an number or a range of numbers; got #{delay}!")
63
+ end
64
+ raise(ArgumentError, 'Delay policy has already been specified!') if @delay_policy
65
+ @delay_policy = ->{Kernel.sleep(rand(delay))}
66
+
67
+ attempt(block)
68
+ end
69
+
70
+ # Specifies reset method that will be called after each failed attempt.
71
+ def with_reset(reset_method, &block)
72
+ raise(ArgumentError, 'Reset method is nil!') unless reset_method
73
+ raise(ArgumentError, 'Reset method has already been speicifed!') if @reset_method
74
+
75
+ @reset_method = reset_method
76
+ attempt(block)
77
+ end
78
+
79
+ # Specifies default method that should be called after all attempts have failed.
80
+ def and_default_to(default_method, &block)
81
+ raise(ArgumentError, 'Default method is nil!') unless default_method
82
+ raise(ArgumentError, 'Default method has already been specified!') if @default_method
83
+
84
+ @default_method = default_method
85
+ attempt(block)
86
+ end
87
+
88
+ # Specifies delay which doubles between failed attempts.
89
+ def with_binary_backoff(initial_delay, &block)
90
+ raise(ArgumentError, "Delay should be a number; got ${initial_delay}!") unless initial_delay.is_a?(Numeric)
91
+ raise(ArgumentError, "Delay should be a positive number; got #{initial_delay}!") unless initial_delay > 0
92
+ raise(ArgumentError, "Delay policy has already been specified!") if @delay_policy
93
+
94
+ @delay_policy = BinaryBackoffPolicy.new(initial_delay)
95
+ attempt(block)
96
+ end
97
+
98
+ # Specifies exceptions
99
+ def with_filter(*exceptions, &block)
100
+ raise(ArgumentError, "Empty exceptions list!") unless exceptions.size > 0
101
+ # Everything must be an exception.
102
+ exceptions.each do |e|
103
+ raise(ArgumentError, "Not an exception: #{e}!") unless e <= Exception
104
+ end
105
+
106
+ raise(ArgumentError, "Exception filter has already been specified!") if @exception_filter
107
+
108
+ @exception_filter = ExceptionTypeFilter.new(exceptions)
109
+ attempt(block)
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,15 @@
1
+ module AttemptThis
2
+ # Implementation of binary backoff policy. Internal use only.
3
+ class BinaryBackoffPolicy
4
+ # Initializer.
5
+ def initialize(initial_delay)
6
+ @delay = initial_delay
7
+ end
8
+
9
+ # Calls the policy.
10
+ def call
11
+ Kernel.sleep(@delay)
12
+ @delay *= 2
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ module AttemptThis
2
+ # Type-based exception filter.
3
+ class ExceptionTypeFilter
4
+ # Initializer.
5
+ def initialize(exception_classes)
6
+ @exception_classes = Array.new(exception_classes)
7
+ end
8
+
9
+ # Tells whether the given exception satisfies the filter.
10
+ def include?(exception)
11
+ @exception_classes.any?{|klass| exception.is_a?(klass)}
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ require 'attempt_this/attempt_object.rb'
2
+
3
+ module AttemptThis
4
+ # Attempts code block until it doesn't throw an exception or the end of enumerator has been reached.
5
+ def attempt(enumerator, &block)
6
+ raise(ArgumentError, 'Nil enumerator!') if enumerator.nil?
7
+
8
+ impl = AttemptObject.new(enumerator)
9
+ impl.attempt(block)
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: attempt_this
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.0
5
+ platform: ruby
6
+ authors:
7
+ - Aliaksei Baturytski
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-05-05 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Retry on exception with configurable number of times, delays, exception
14
+ filters, and fall back strategies
15
+ email: abaturytski@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/attempt_this.rb
21
+ - lib/attempt_this/attempt_object.rb
22
+ - lib/attempt_this/binary_backoff_policy.rb
23
+ - lib/attempt_this/exception_type_filter.rb
24
+ homepage: https://github.com/aliakb/attempt_this
25
+ licenses: []
26
+ metadata: {}
27
+ post_install_message:
28
+ rdoc_options: []
29
+ require_paths:
30
+ - lib
31
+ required_ruby_version: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - '>='
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ required_rubygems_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubyforge_project:
43
+ rubygems_version: 2.0.0
44
+ signing_key:
45
+ specification_version: 4
46
+ summary: Retry policy mix-in
47
+ test_files: []