ya_circuit_breaker 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 73c83613b11f39499746959dafbe0d55d2f2e309
4
- data.tar.gz: b7bbe8cfd8fd6232a4bafd7f3b49d64194151969
3
+ metadata.gz: 9ffa87cc6c8a50ade120114ace1c9d8e98e7ba4a
4
+ data.tar.gz: d119cd8c1448de2b4225114a9dc938e453b8c0a9
5
5
  SHA512:
6
- metadata.gz: d4b170420e181aa1173ae9e6541bd8eddab1a8ef5d0c9c0610e78bfd4fb8b1b4722339a25f815bc5f5a4fd3ad0adc0105cbf17d911f8f93aa4abf00bf01290f0
7
- data.tar.gz: b8f01d55e62c0f02c385fe6dc3a78160a65d2616858878e24760e0295a97ab6c7be382fe86bb3ecb389c0833c9882d2e1ddeacd3fecc742d56e46ba9224bab25
6
+ metadata.gz: 9f64c4eaceb986bc3a70e3a5e60a284eb6fa6d74ba421318ddd49ae99e921445f9a94ffc0a35c3d58d722841cfbfea1842e7967d81a3577a29c7c42b8539b3e5
7
+ data.tar.gz: e5df6e2f23df1d8a69ebb09d194ecc698eeda630f93506bd64e9ed696519b4256d40bdfea129429dde6ecc1e77cd59723ac068d198c2e0e9242d1930355e9703
@@ -0,0 +1,3 @@
1
+ 2014-04-28 Multiple exceptions handling and Proc support in addition to truncated exponential reset timeouts logic
2
+
3
+ 2014-04-24 Initial version
data/README.md CHANGED
@@ -31,7 +31,10 @@ options = {
31
31
  # invocation timeout in seconds
32
32
  invocation_timeout: 0.5,
33
33
  # a list of timeouts for consecutive failures in seconds. can be used for exponential backoff
34
- reset_timeouts: [2, 4, 8, 16, 32, 64, 128]
34
+ # a Proc can be also passed instead, that can operate on a number of retries after circuit breaker trips
35
+ reset_timeouts: [2, 4, 8, 16, 32, 64, 128], # or Proc.new {|retry| retry * 10}
36
+ # a list of errors or exceptions that indicates outtage of service
37
+ errors_handled: [Redis::CommandError]
35
38
  }
36
39
 
37
40
  circuit_breaker = CircuitBreaker::Basic.new(options)
@@ -44,6 +47,8 @@ rescue CircuitBreaker::CircuitBrokenError
44
47
  $stderr.puts "Circuit tripped"
45
48
  rescue Timeout::Error
46
49
  $stderr.puts "Call took too long"
50
+ resque Redis::CommandError # from errors_handled
51
+ $stderr.puts "One of the errors indicating outtage of the service"
47
52
  rescue Error
48
53
  $stderr.puts "Error thrown by 'http_api_call'"
49
54
  end
@@ -9,7 +9,8 @@ module CircuitBreaker
9
9
  DEFAULTS = {
10
10
  failure_threshold: 5,
11
11
  invocation_timeout: 2,
12
- reset_timeouts: 10
12
+ reset_timeouts: 10,
13
+ errors_handled: [],
13
14
  }
14
15
 
15
16
  attr_reader :failure_count, :last_failure_time, :failure_threshold
@@ -18,7 +19,8 @@ module CircuitBreaker
18
19
  options = DEFAULTS.merge(options)
19
20
  @failure_threshold = options[:failure_threshold]
20
21
  @invocation_timeout = options[:invocation_timeout]
21
- @reset_timeouts = Array(options[:reset_timeouts])
22
+ @reset_timeouts = options[:reset_timeouts].is_a?(Proc) ? options[:reset_timeouts] : Array(options[:reset_timeouts])
23
+ @errors_handled = Array(options[:errors_handled])
22
24
  @last_failure_time = nil
23
25
  @failure_count = 0
24
26
  end
@@ -50,7 +52,13 @@ module CircuitBreaker
50
52
  end
51
53
 
52
54
  def reset_timeout
53
- @reset_timeouts[[@reset_timeouts.size - 1, retry_counter].min]
55
+ if @reset_timeouts.is_a? Proc
56
+ return @reset_timeouts.call retry_counter
57
+ else
58
+ index = [@reset_timeouts.size - 1, retry_counter].min
59
+ @reset_timeouts[index]
60
+ end
61
+
54
62
  end
55
63
 
56
64
 
@@ -73,8 +81,8 @@ module CircuitBreaker
73
81
  block.call if block_given?
74
82
  end
75
83
  reset!
76
- rescue Timeout::Error
77
- record_failure
84
+ rescue Exception => e
85
+ record_failure if e.class == Timeout::Error || @errors_handled.include?(e.class)
78
86
  raise
79
87
  end
80
88
  else
@@ -1,3 +1,3 @@
1
1
  module CircuitBreaker
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -63,6 +63,17 @@ describe CircuitBreaker::Basic do
63
63
  end
64
64
  end
65
65
 
66
+ it "should trip after the failure threshold has been exceeded" do
67
+ circuit_breaker = CircuitBreaker::Basic.new(failure_threshold: 1, invocation_timeout: 0.1, errors_handled: ArgumentError)
68
+
69
+ assert_raises ArgumentError do
70
+ circuit_breaker.execute do
71
+ raise ArgumentError
72
+ end
73
+ end
74
+ assert circuit_breaker.open?, "Circuit should be open"
75
+ end
76
+
66
77
  it "should reset after reset timeout" do
67
78
  reset_timeouts = 0.1
68
79
  circuit_breaker = CircuitBreaker::Basic.new(reset_timeouts: reset_timeouts)
@@ -77,6 +88,23 @@ describe CircuitBreaker::Basic do
77
88
  assert circuit_breaker.half_open?
78
89
  end
79
90
 
91
+ it "should handle proc as reset timeout" do
92
+ reset_timeouts = Proc.new {|retry_counter| retry_counter + 1}
93
+ circuit_breaker = CircuitBreaker::Basic.new(failure_threshold: 1, reset_timeouts: reset_timeouts, errors_handled: ArgumentError)
94
+
95
+ assert_raises ArgumentError do
96
+ circuit_breaker.execute do
97
+ raise ArgumentError
98
+ end
99
+ end
100
+
101
+ assert circuit_breaker.open?, "Circuit should be open"
102
+
103
+ sleep(reset_timeouts.call 1)
104
+
105
+ assert circuit_breaker.half_open?
106
+ end
107
+
80
108
  it "should change from half open to closed on success" do
81
109
  reset_timeouts = 0.1
82
110
  circuit_breaker = CircuitBreaker::Basic.new(reset_timeouts: reset_timeouts)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ya_circuit_breaker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrick Huesler
@@ -9,34 +9,34 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-04-24 00:00:00.000000000 Z
12
+ date: 2014-04-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - "~>"
18
+ - - ~>
19
19
  - !ruby/object:Gem::Version
20
20
  version: '1.5'
21
21
  type: :development
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - "~>"
25
+ - - ~>
26
26
  - !ruby/object:Gem::Version
27
27
  version: '1.5'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: rake
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - ">="
32
+ - - '>='
33
33
  - !ruby/object:Gem::Version
34
34
  version: '0'
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - ">="
39
+ - - '>='
40
40
  - !ruby/object:Gem::Version
41
41
  version: '0'
42
42
  description: Prevent long running external calls from blocking an application
@@ -47,8 +47,9 @@ executables: []
47
47
  extensions: []
48
48
  extra_rdoc_files: []
49
49
  files:
50
- - ".gitignore"
51
- - ".travis.yml"
50
+ - .gitignore
51
+ - .travis.yml
52
+ - ChangeLog
52
53
  - Gemfile
53
54
  - LICENSE.txt
54
55
  - README.md
@@ -69,17 +70,17 @@ require_paths:
69
70
  - lib
70
71
  required_ruby_version: !ruby/object:Gem::Requirement
71
72
  requirements:
72
- - - ">="
73
+ - - '>='
73
74
  - !ruby/object:Gem::Version
74
75
  version: '0'
75
76
  required_rubygems_version: !ruby/object:Gem::Requirement
76
77
  requirements:
77
- - - ">="
78
+ - - '>='
78
79
  - !ruby/object:Gem::Version
79
80
  version: '0'
80
81
  requirements: []
81
82
  rubyforge_project:
82
- rubygems_version: 2.2.1
83
+ rubygems_version: 2.0.3
83
84
  signing_key:
84
85
  specification_version: 4
85
86
  summary: Basic circuit breaker in Ruby