breaker_machines 0.17.0 → 0.19.0

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
  SHA256:
3
- metadata.gz: 4116461b731bfc94e0773301a5ce27d8a118e4b8d8adf033e1b53b304f2538e5
4
- data.tar.gz: 6cf9ed874a11f2f33db5c92f13875686260b65267c933dcb1d2cc1d994264a3f
3
+ metadata.gz: 6172f37c8307d66dbacea1526038a00deb457e16ea404ea877cd4d4c8f5c18bd
4
+ data.tar.gz: e246c2d0d5a4df91003105a4ccb2ee5d00593bda8a4d339f8eeb5fd28ac16d41
5
5
  SHA512:
6
- metadata.gz: fb362d48c18c9706cdffc79634af898403d9cd349a4bef73da399cbe177eaab435f83a8143b33d7c420745b4f4969c682a184269b8849893123244b98b7b2eea
7
- data.tar.gz: afd84f6bc4ac312d7bc7cbbcc1c9710fdb550694e0e32c4598bf04d0658af2fe5c23a399fbdfa2801e99dbfe610c3fd44458df8b33569e948b77757bb5fd7208
6
+ metadata.gz: b4145bd486e2645b57eab3058671ba08143ac1422a11a68ba00b3079d3c35981d6c8b8c470e2f0de75af59c2799d780a360f74739e43b1022bfd447de6bc5dd0
7
+ data.tar.gz: 00f7382d4b5ea05c057c3ba77cf6289d3fe96e5a74351b5cc5280d8106240add688156b2b2a76ae1c609bb4c330bbec60745185a9abb1640bde2e5499c040218
@@ -11,11 +11,11 @@ module BreakerMachines
11
11
  include Circuit::AsyncStateManagement
12
12
 
13
13
  # Additional async-specific methods
14
- def call_async(&block)
14
+ def call_async(&)
15
15
  require 'async' unless defined?(::Async)
16
16
 
17
17
  Async do
18
- call(&block)
18
+ call(&)
19
19
  end
20
20
  end
21
21
 
@@ -57,23 +57,15 @@ module BreakerMachines
57
57
 
58
58
  # Execute a block with circuit breaker protection
59
59
  #
60
+ # Admission, the open -> half-open cooldown, and half-open probe limits run
61
+ # in the native circuit. A StandardError counts as a failure and is
62
+ # re-raised; other exceptions and throw/break pass through uncounted.
63
+ #
60
64
  # @yield Block to execute
61
65
  # @return Result of the block
62
- # @raise [CircuitOpenError] if circuit is open
63
- def call
64
- raise CircuitOpenError, "Circuit '#{@name}' is open" if open?
65
-
66
- start_time = BreakerMachines.monotonic_time
67
- begin
68
- result = yield
69
- duration = BreakerMachines.monotonic_time - start_time
70
- @native_circuit.record_success(duration)
71
- result
72
- rescue StandardError => _e
73
- duration = BreakerMachines.monotonic_time - start_time
74
- @native_circuit.record_failure(duration)
75
- raise
76
- end
66
+ # @raise [CircuitOpenError] if circuit is open or its probe slots are taken
67
+ def call(&)
68
+ @native_circuit.call(&)
77
69
  end
78
70
 
79
71
  # Check if circuit is open
@@ -88,8 +80,14 @@ module BreakerMachines
88
80
  @native_circuit.is_closed
89
81
  end
90
82
 
83
+ # Check if circuit is half-open (probing for recovery)
84
+ # @return [Boolean]
85
+ def half_open?
86
+ @native_circuit.is_half_open
87
+ end
88
+
91
89
  # Get current state name
92
- # @return [String] 'open' or 'closed'
90
+ # @return [String] 'closed', 'open', or 'half_open'
93
91
  def state
94
92
  @native_circuit.state_name
95
93
  end
@@ -160,7 +160,7 @@ module BreakerMachines
160
160
  @config[:exceptions] = exceptions
161
161
  end
162
162
 
163
- def fiber_safe(enabled = true) # rubocop:disable Style/OptionalBooleanParameter
163
+ def fiber_safe(enabled = true)
164
164
  @config[:fiber_safe] = enabled
165
165
  end
166
166
 
@@ -39,12 +39,12 @@ module BreakerMachines
39
39
  end
40
40
  end
41
41
 
42
- def circuit(name, &block)
42
+ def circuit(name, &)
43
43
  @circuits ||= {}
44
44
 
45
45
  if block_given?
46
46
  builder = DSL::CircuitBuilder.new
47
- builder.instance_eval(&block)
47
+ builder.instance_eval(&)
48
48
  @circuits[name] = builder.config
49
49
  end
50
50
 
@@ -52,12 +52,12 @@ module BreakerMachines
52
52
  end
53
53
 
54
54
  # Define a cascading circuit breaker that can trip dependent circuits
55
- def cascade_circuit(name, &block)
55
+ def cascade_circuit(name, &)
56
56
  @circuits ||= {}
57
57
 
58
58
  if block_given?
59
59
  builder = DSL::CascadingCircuitBuilder.new
60
- builder.instance_eval(&block)
60
+ builder.instance_eval(&)
61
61
  @circuits[name] = builder.config.merge(circuit_type: :cascading)
62
62
  end
63
63
 
@@ -81,12 +81,12 @@ module BreakerMachines
81
81
  end
82
82
 
83
83
  # Define reusable circuit templates
84
- def circuit_template(name, &block)
84
+ def circuit_template(name, &)
85
85
  @circuit_templates ||= {}
86
86
 
87
87
  if block_given?
88
88
  builder = DSL::CircuitBuilder.new
89
- builder.instance_eval(&block)
89
+ builder.instance_eval(&)
90
90
  @circuit_templates[name] = builder.config
91
91
  end
92
92
 
@@ -60,7 +60,7 @@ module BreakerMachines
60
60
  end
61
61
 
62
62
  # Force open a circuit by name
63
- def force_open(name) # rubocop:disable Naming/PredicateMethod
63
+ def force_open(name)
64
64
  circuits = find_by_name(name)
65
65
  return false if circuits.empty?
66
66
 
@@ -69,7 +69,7 @@ module BreakerMachines
69
69
  end
70
70
 
71
71
  # Force close a circuit by name
72
- def force_close(name) # rubocop:disable Naming/PredicateMethod
72
+ def force_close(name)
73
73
  circuits = find_by_name(name)
74
74
  return false if circuits.empty?
75
75
 
@@ -78,7 +78,7 @@ module BreakerMachines
78
78
  end
79
79
 
80
80
  # Reset a circuit by name
81
- def reset(name) # rubocop:disable Naming/PredicateMethod
81
+ def reset(name)
82
82
  circuits = find_by_name(name)
83
83
  return false if circuits.empty?
84
84
 
@@ -80,7 +80,7 @@ module BreakerMachines
80
80
 
81
81
  private
82
82
 
83
- def execute_with_fallback(method, *args, **kwargs)
83
+ def execute_with_fallback(method, *, **kwargs)
84
84
  chain_started_at = BreakerMachines.monotonic_time
85
85
  attempted_backends = []
86
86
 
@@ -100,9 +100,9 @@ module BreakerMachines
100
100
 
101
101
  result = backend.with_timeout(config[:timeout]) do
102
102
  if kwargs.any?
103
- backend.send(method, *args, **kwargs)
103
+ backend.send(method, *, **kwargs)
104
104
  else
105
- backend.send(method, *args)
105
+ backend.send(method, *)
106
106
  end
107
107
  end
108
108
 
@@ -58,10 +58,12 @@ module BreakerMachines
58
58
  timestamp: current_time
59
59
  }
60
60
 
61
- # Clean old events periodically (every 100 events)
62
- return unless events.size > 100
61
+ # Keep 5 minutes of history. Events are appended oldest first, so only
62
+ # scan once the oldest has aged out; scanning on every write made each
63
+ # write O(n) once more than 100 events were retained.
64
+ cutoff_time = current_time - 300
65
+ return unless events.size > 100 && events.first[:timestamp] < cutoff_time
63
66
 
64
- cutoff_time = current_time - 300 # Keep 5 minutes of history
65
67
  events.delete_if { |e| e[:timestamp] < cutoff_time }
66
68
  end
67
69
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BreakerMachines
4
- VERSION = '0.17.0'
4
+ VERSION = '0.19.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: breaker_machines
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.0
4
+ version: 0.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Abdelkader Boudih
@@ -29,14 +29,14 @@ dependencies:
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '0.2'
32
+ version: '0.9'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '0.2'
39
+ version: '0.9'
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: concurrent-ruby
42
42
  requirement: !ruby/object:Gem::Requirement
@@ -55,16 +55,16 @@ dependencies:
55
55
  name: state_machines
56
56
  requirement: !ruby/object:Gem::Requirement
57
57
  requirements:
58
- - - ">="
58
+ - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: 0.200.0
60
+ version: '0.202'
61
61
  type: :runtime
62
62
  prerelease: false
63
63
  version_requirements: !ruby/object:Gem::Requirement
64
64
  requirements:
65
- - - ">="
65
+ - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: 0.200.0
67
+ version: '0.202'
68
68
  - !ruby/object:Gem::Dependency
69
69
  name: zeitwerk
70
70
  requirement: !ruby/object:Gem::Requirement
@@ -222,14 +222,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
222
222
  requirements:
223
223
  - - ">="
224
224
  - !ruby/object:Gem::Version
225
- version: 3.3.0
225
+ version: 4.0.0
226
226
  required_rubygems_version: !ruby/object:Gem::Requirement
227
227
  requirements:
228
228
  - - ">="
229
229
  - !ruby/object:Gem::Version
230
230
  version: '0'
231
231
  requirements: []
232
- rubygems_version: 3.6.9
232
+ rubygems_version: 4.0.20
233
233
  specification_version: 4
234
234
  summary: Circuit breaker implementation for Ruby with a clean DSL and state_machines
235
235
  under the hood