ya_circuit_breaker 0.0.2 → 0.0.3

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: 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