stoplight 4.1.1 → 5.0.1
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 +4 -4
- data/README.md +288 -354
- data/lib/stoplight/admin/actions/action.rb +24 -0
- data/lib/stoplight/admin/actions/lock.rb +23 -0
- data/lib/stoplight/admin/actions/lock_all_green.rb +18 -0
- data/lib/stoplight/admin/actions/lock_green.rb +23 -0
- data/lib/stoplight/admin/actions/lock_red.rb +23 -0
- data/lib/stoplight/admin/actions/stats.rb +27 -0
- data/lib/stoplight/admin/actions/unlock.rb +23 -0
- data/lib/stoplight/admin/dependencies.rb +50 -0
- data/lib/stoplight/admin/helpers.rb +27 -0
- data/lib/stoplight/admin/lights_repository/light.rb +155 -0
- data/lib/stoplight/admin/lights_repository.rb +74 -0
- data/lib/stoplight/admin/lights_stats.rb +77 -0
- data/lib/stoplight/admin/views/_card.erb +120 -0
- data/lib/stoplight/admin/views/index.erb +36 -0
- data/lib/stoplight/admin/views/layout.erb +66 -0
- data/lib/stoplight/admin.rb +68 -0
- data/lib/stoplight/color.rb +3 -3
- data/lib/stoplight/config/config_provider.rb +62 -0
- data/lib/stoplight/config/library_default_config.rb +29 -0
- data/lib/stoplight/config/user_default_config.rb +83 -0
- data/lib/stoplight/data_store/base.rb +59 -33
- data/lib/stoplight/data_store/fail_safe.rb +105 -0
- data/lib/stoplight/data_store/memory.rb +257 -50
- data/lib/stoplight/data_store/redis/get_metadata.lua +38 -0
- data/lib/stoplight/data_store/redis/lua.rb +23 -0
- data/lib/stoplight/data_store/redis/record_failure.lua +36 -0
- data/lib/stoplight/data_store/redis/record_success.lua +35 -0
- data/lib/stoplight/data_store/redis/transition_to_green.lua +10 -0
- data/lib/stoplight/data_store/redis/transition_to_red.lua +10 -0
- data/lib/stoplight/data_store/redis/transition_to_yellow.lua +9 -0
- data/lib/stoplight/data_store/redis.rb +345 -106
- data/lib/stoplight/default.rb +11 -9
- data/lib/stoplight/error.rb +1 -13
- data/lib/stoplight/failure.rb +14 -13
- data/lib/stoplight/light/config.rb +118 -0
- data/lib/stoplight/light/configuration_builder_interface.rb +128 -0
- data/lib/stoplight/light/green_run_strategy.rb +53 -0
- data/lib/stoplight/light/red_run_strategy.rb +26 -0
- data/lib/stoplight/light/run_strategy.rb +30 -0
- data/lib/stoplight/light/yellow_run_strategy.rb +78 -0
- data/lib/stoplight/light.rb +164 -84
- data/lib/stoplight/metadata.rb +71 -0
- data/lib/stoplight/notifier/base.rb +14 -7
- data/lib/stoplight/notifier/fail_safe.rb +67 -0
- data/lib/stoplight/notifier/generic.rb +54 -5
- data/lib/stoplight/rspec/generic_notifier.rb +11 -12
- data/lib/stoplight/rspec.rb +1 -1
- data/lib/stoplight/state.rb +3 -3
- data/lib/stoplight/traffic_control/base.rb +35 -0
- data/lib/stoplight/traffic_control/consecutive_failures.rb +43 -0
- data/lib/stoplight/traffic_recovery/base.rb +51 -0
- data/lib/stoplight/traffic_recovery/single_success.rb +35 -0
- data/lib/stoplight/version.rb +1 -1
- data/lib/stoplight.rb +111 -51
- metadata +49 -98
- data/lib/stoplight/builder.rb +0 -70
- data/lib/stoplight/circuit_breaker.rb +0 -102
- data/lib/stoplight/configurable.rb +0 -95
- data/lib/stoplight/configuration.rb +0 -126
- data/lib/stoplight/light/deprecated.rb +0 -44
- data/lib/stoplight/light/lockable.rb +0 -45
- data/lib/stoplight/light/runnable.rb +0 -127
- data/lib/stoplight/notifier.rb +0 -6
- data/spec/spec_helper.rb +0 -22
- data/spec/stoplight/builder_spec.rb +0 -165
- data/spec/stoplight/circuit_breaker_spec.rb +0 -43
- data/spec/stoplight/color_spec.rb +0 -39
- data/spec/stoplight/configurable_spec.rb +0 -25
- data/spec/stoplight/data_store/base_spec.rb +0 -71
- data/spec/stoplight/data_store/memory_spec.rb +0 -22
- data/spec/stoplight/data_store/redis_spec.rb +0 -45
- data/spec/stoplight/data_store_spec.rb +0 -9
- data/spec/stoplight/default_spec.rb +0 -80
- data/spec/stoplight/error_spec.rb +0 -39
- data/spec/stoplight/failure_spec.rb +0 -108
- data/spec/stoplight/light/lockable_spec.rb +0 -93
- data/spec/stoplight/light/runnable_spec.rb +0 -38
- data/spec/stoplight/light_spec.rb +0 -156
- data/spec/stoplight/notifier/base_spec.rb +0 -18
- data/spec/stoplight/notifier/generic_spec.rb +0 -50
- data/spec/stoplight/notifier/io_spec.rb +0 -41
- data/spec/stoplight/notifier/logger_spec.rb +0 -75
- data/spec/stoplight/notifier_spec.rb +0 -9
- data/spec/stoplight/state_spec.rb +0 -39
- data/spec/stoplight/version_spec.rb +0 -9
- data/spec/stoplight_spec.rb +0 -32
- data/spec/support/configurable.rb +0 -69
- data/spec/support/data_store/base/clear_failures.rb +0 -24
- data/spec/support/data_store/base/clear_state.rb +0 -20
- data/spec/support/data_store/base/get_all.rb +0 -44
- data/spec/support/data_store/base/get_failures.rb +0 -30
- data/spec/support/data_store/base/get_state.rb +0 -7
- data/spec/support/data_store/base/names.rb +0 -29
- data/spec/support/data_store/base/record_failures.rb +0 -70
- data/spec/support/data_store/base/set_state.rb +0 -15
- data/spec/support/data_store/base/with_notification_lock.rb +0 -27
- data/spec/support/data_store/base.rb +0 -21
- data/spec/support/database_cleaner.rb +0 -26
- data/spec/support/exception_helpers.rb +0 -9
- data/spec/support/light/runnable/color.rb +0 -79
- data/spec/support/light/runnable/run.rb +0 -247
- data/spec/support/light/runnable/state.rb +0 -31
- data/spec/support/light/runnable.rb +0 -5
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Stoplight
|
4
|
+
module TrafficRecovery
|
5
|
+
# Strategies for determining how to recover traffic flow through the Stoplight.
|
6
|
+
# These strategies evaluate recovery metrics to decide which color the Stoplight should
|
7
|
+
# transition to during the recovery process.
|
8
|
+
#
|
9
|
+
# @example Creating a custom traffic recovery strategy
|
10
|
+
# class GradualRecovery < Stoplight::TrafficRecovery::Base
|
11
|
+
# def initialize(min_success_rate: 0.8, min_samples: 100)
|
12
|
+
# @min_success_rate = min_success_rate
|
13
|
+
# @min_samples = min_samples
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# def determine_color(config, metadata)
|
17
|
+
# total_probes = metadata.recovery_probe_successes + metadata.recovery_probe_errors
|
18
|
+
#
|
19
|
+
# if total_probes < @min_samples
|
20
|
+
# return Color::YELLOW # Keep recovering, not enough samples
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# success_rate = metadata.recovery_probe_successes.fdiv(total_probes)
|
24
|
+
# if success_rate >= @min_success_rate
|
25
|
+
# Color::GREEN # Recovery successful
|
26
|
+
# elsif success_rate <= 0.2
|
27
|
+
# Color::RED # Recovery failed, too many errors
|
28
|
+
# else
|
29
|
+
# Color::YELLOW # Continue recovery
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# @abstract
|
35
|
+
# @api private
|
36
|
+
class Base
|
37
|
+
# Determines the appropriate recovery state based on the Stoplight's
|
38
|
+
# current metrics and recovery progress.
|
39
|
+
#
|
40
|
+
# @param config [Stoplight::Light::Config]
|
41
|
+
# @param metadata [Stoplight::Metadata]
|
42
|
+
# @return [String] One of the Stoplight::Color constants:
|
43
|
+
# - Stoplight::Color::RED: Recovery failed, block all traffic
|
44
|
+
# - Stoplight::Color::YELLOW: Continue recovery process
|
45
|
+
# - Stoplight::Color::GREEN: Recovery successful, return to normal traffic flow
|
46
|
+
def determine_color(config, metadata)
|
47
|
+
raise NotImplementedError
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Stoplight
|
4
|
+
module TrafficRecovery
|
5
|
+
# A basic strategy that recovers traffic flow after a successful recovery probe.
|
6
|
+
#
|
7
|
+
# This strategy allows traffic to resume when a single successful probe
|
8
|
+
# occurs after the Stoplight has been in red state. It's a simple "one success and we're back"
|
9
|
+
# approach.
|
10
|
+
#
|
11
|
+
# @example Basic usage
|
12
|
+
# config = Stoplight::Light::Config.new(cool_off_time: 60)
|
13
|
+
# strategy = Stoplight::TrafficRecovery::SingleSuccess.new
|
14
|
+
#
|
15
|
+
# After the Stoplight turns red:
|
16
|
+
# - The Stoplight will wait for the cool-off period (60 seconds)
|
17
|
+
# - Then enter the recovery phase (YELLOW color)
|
18
|
+
# - The first successful probe will resume normal traffic flow (green color)
|
19
|
+
# @api private
|
20
|
+
class SingleSuccess < Base
|
21
|
+
# @param config [Stoplight::Light::Config]
|
22
|
+
# @param metadata [Stoplight::Metadata]
|
23
|
+
# @return [String]
|
24
|
+
def determine_color(config, metadata)
|
25
|
+
recovery_started_at = metadata.recovery_started_at || metadata.recovery_scheduled_after
|
26
|
+
last_success_at = metadata.last_success_at
|
27
|
+
if last_success_at && recovery_started_at <= last_success_at
|
28
|
+
Color::GREEN
|
29
|
+
else
|
30
|
+
Color::RED
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/stoplight/version.rb
CHANGED
data/lib/stoplight.rb
CHANGED
@@ -1,63 +1,123 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
class << self
|
5
|
-
# @!attribute default_data_store
|
6
|
-
# @return [DataStore::Base]
|
7
|
-
attr_accessor :default_data_store
|
8
|
-
|
9
|
-
# @!attribute default_notifiers
|
10
|
-
# @return [Array<Notifier::Base>]
|
11
|
-
attr_accessor :default_notifiers
|
12
|
-
|
13
|
-
# @!attribute default_error_notifier
|
14
|
-
# @return [Proc]
|
15
|
-
attr_accessor :default_error_notifier
|
16
|
-
end
|
17
|
-
end
|
3
|
+
require "zeitwerk"
|
18
4
|
|
19
|
-
|
5
|
+
loader = Zeitwerk::Loader.for_gem
|
6
|
+
loader.inflector.inflect("io" => "IO")
|
7
|
+
loader.do_not_eager_load(
|
8
|
+
"#{__dir__}/stoplight/data_store",
|
9
|
+
"#{__dir__}/stoplight/admin",
|
10
|
+
"#{__dir__}/stoplight/admin.rb"
|
11
|
+
)
|
12
|
+
loader.ignore("#{__dir__}/stoplight/rspec.rb", "#{__dir__}/stoplight/rspec")
|
13
|
+
loader.setup
|
20
14
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
require 'stoplight/state'
|
15
|
+
module Stoplight # rubocop:disable Style/Documentation
|
16
|
+
CONFIG_MUTEX = Mutex.new
|
17
|
+
private_constant :CONFIG_MUTEX
|
25
18
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
require 'stoplight/data_store/redis'
|
19
|
+
class << self
|
20
|
+
ALREADY_CONFIGURED_WARNING = "Stoplight must be configured only once"
|
21
|
+
private_constant :ALREADY_CONFIGURED_WARNING
|
30
22
|
|
31
|
-
|
32
|
-
|
33
|
-
|
23
|
+
# Configures the Stoplight library.
|
24
|
+
#
|
25
|
+
# This method allows you to set up the library's configuration using a block.
|
26
|
+
# It raises an error if called more than once.
|
27
|
+
#
|
28
|
+
# @yield [config] Provides a configuration object to the block.
|
29
|
+
# @yieldparam config [Stoplight::Config::ProgrammaticConfig] The configuration object.
|
30
|
+
# @raise [Stoplight::Error::ConfigurationError] If the library is already configured.
|
31
|
+
# @return [void]
|
32
|
+
#
|
33
|
+
# @example
|
34
|
+
# Stoplight.configure do |config|
|
35
|
+
# config.window_size = 14
|
36
|
+
# config.data_store = Stoplight::DataStore::Redis.new(redis_client)
|
37
|
+
# config.notifiers = [Stoplight::Notifier::IO.new($stdout)]
|
38
|
+
# config.cool_off_time = 120
|
39
|
+
# config.threshold = 5
|
40
|
+
# config.tracked_errors = [StandardError]
|
41
|
+
# config.skipped_errors = [RuntimeError]
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# @note It is not recommended to call this method multiple times because after reconfiguring Stoplight
|
45
|
+
# it will not be possible to change the configuration of existing circuit breakers. If you do so, the method
|
46
|
+
# produces a warning:
|
47
|
+
#
|
48
|
+
# "Stoplight reconfigured. Existing circuit breakers will not see the new configuration. New
|
49
|
+
# configuration: #<Stoplight::Config::ConfigProvider cool_off_time=32, threshold=3, window_size=94, tracked_errors=StandardError, skipped_errors=NoMemoryError,ScriptError,SecurityError,SignalException,SystemExit,SystemStackError, data_store=Stoplight::DataStore::Memory>\n"
|
50
|
+
#
|
51
|
+
# If you really know what you are doing, you can pass the +trust_me_im_an_engineer+ parameter as +true+ to
|
52
|
+
# suppress this warning, which could be useful in test environments.
|
53
|
+
#
|
54
|
+
def configure(trust_me_im_an_engineer: false)
|
55
|
+
user_defaults = Config::UserDefaultConfig.new
|
56
|
+
yield(user_defaults) if block_given?
|
34
57
|
|
35
|
-
|
36
|
-
require 'stoplight/notifier/logger'
|
58
|
+
reconfigured = !@config_provider.nil?
|
37
59
|
|
38
|
-
|
60
|
+
@config_provider = Config::ConfigProvider.new(
|
61
|
+
user_default_config: user_defaults.freeze,
|
62
|
+
library_default_config: Config::LibraryDefaultConfig.new
|
63
|
+
).tap do
|
64
|
+
if reconfigured && !trust_me_im_an_engineer
|
65
|
+
warn(
|
66
|
+
"Stoplight reconfigured. Existing circuit breakers will not see new configuration. " \
|
67
|
+
"New configuration: #{@config_provider.inspect}"
|
68
|
+
)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
39
72
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
73
|
+
# Retrieves the current configuration provider.
|
74
|
+
#
|
75
|
+
# @return [Stoplight::Config::ConfigProvider]
|
76
|
+
# @api private
|
77
|
+
def config_provider
|
78
|
+
CONFIG_MUTEX.synchronize do
|
79
|
+
@config_provider ||= configure
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
44
83
|
end
|
45
84
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
#
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
85
|
+
# Creates a new Stoplight circuit breaker with the given name and settings.
|
86
|
+
#
|
87
|
+
# @param name [String] The name of the circuit breaker.
|
88
|
+
# @param settings [Hash] Optional settings to configure the circuit breaker.
|
89
|
+
# @option settings [Numeric] :cool_off_time The time to wait before resetting the circuit breaker.
|
90
|
+
# @option settings [Stoplight::DataStore::Base] :data_store The data store to use for storing state.
|
91
|
+
# @option settings [Proc] :error_notifier A proc to handle error notifications.
|
92
|
+
# @option settings [Array<Stoplight::Notifier::Base>] :notifiers A list of notifiers to use.
|
93
|
+
# @option settings [Numeric] :threshold The failure threshold to trip the circuit breaker.
|
94
|
+
# @option settings [Numeric] :window_size The size of the rolling window for failure tracking.
|
95
|
+
# @option settings [Array<StandardError>] :tracked_errors A list of errors to track.
|
96
|
+
# @option settings [Array<Exception>] :skipped_errors A list of errors to skip.
|
97
|
+
#
|
98
|
+
# @return [Stoplight::Light] A new circuit breaker instance.
|
99
|
+
# @raise [ArgumentError] If an unknown option is provided in the settings.
|
100
|
+
#
|
101
|
+
# @example configure circuit breaker behavior
|
102
|
+
# light = Stoplight("Payment API", window_size: 300, threshold: 5, cool_off_time: 60)
|
103
|
+
#
|
104
|
+
# @example configure data store
|
105
|
+
# light = Stoplight("Payment API", data_store: Stoplight::DataStore::Redis.new(redis_client))
|
106
|
+
#
|
107
|
+
# In the example below, the +TimeoutError+ and +NetworkError+ exceptions
|
108
|
+
# will be counted towards the threshold for moving the circuit breaker into the red state.
|
109
|
+
# If not configured, the default tracked error is +StandardError+.
|
110
|
+
#
|
111
|
+
# @example configure tracked errors
|
112
|
+
# light = Stoplight("Payment API", tracked_errors: [TimeoutError, NetworkError])
|
113
|
+
#
|
114
|
+
# In the example below , the +ActiveRecord::RecordNotFound+ doesn't
|
115
|
+
# move the circuit breaker into the red state.
|
116
|
+
#
|
117
|
+
# @example configure skipped errors
|
118
|
+
# light = Stoplight("Payment API", skipped_errors: [ActiveRecord::RecordNotFound])
|
119
|
+
#
|
120
|
+
def Stoplight(name, **settings) # rubocop:disable Naming/MethodName
|
121
|
+
config = Stoplight.config_provider.provide(name, **settings)
|
122
|
+
Stoplight::Light.new(config)
|
63
123
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stoplight
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cameron Desautels
|
@@ -10,22 +10,22 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2025-
|
13
|
+
date: 2025-06-20 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
|
-
name:
|
16
|
+
name: zeitwerk
|
17
17
|
requirement: !ruby/object:Gem::Requirement
|
18
18
|
requirements:
|
19
|
-
- - "
|
19
|
+
- - ">="
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: '
|
21
|
+
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
|
-
- - "
|
26
|
+
- - ">="
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
version: '
|
28
|
+
version: '0'
|
29
29
|
description: An implementation of the circuit breaker pattern.
|
30
30
|
email:
|
31
31
|
- camdez@gmail.com
|
@@ -39,71 +39,62 @@ files:
|
|
39
39
|
- LICENSE.md
|
40
40
|
- README.md
|
41
41
|
- lib/stoplight.rb
|
42
|
-
- lib/stoplight/
|
43
|
-
- lib/stoplight/
|
42
|
+
- lib/stoplight/admin.rb
|
43
|
+
- lib/stoplight/admin/actions/action.rb
|
44
|
+
- lib/stoplight/admin/actions/lock.rb
|
45
|
+
- lib/stoplight/admin/actions/lock_all_green.rb
|
46
|
+
- lib/stoplight/admin/actions/lock_green.rb
|
47
|
+
- lib/stoplight/admin/actions/lock_red.rb
|
48
|
+
- lib/stoplight/admin/actions/stats.rb
|
49
|
+
- lib/stoplight/admin/actions/unlock.rb
|
50
|
+
- lib/stoplight/admin/dependencies.rb
|
51
|
+
- lib/stoplight/admin/helpers.rb
|
52
|
+
- lib/stoplight/admin/lights_repository.rb
|
53
|
+
- lib/stoplight/admin/lights_repository/light.rb
|
54
|
+
- lib/stoplight/admin/lights_stats.rb
|
55
|
+
- lib/stoplight/admin/views/_card.erb
|
56
|
+
- lib/stoplight/admin/views/index.erb
|
57
|
+
- lib/stoplight/admin/views/layout.erb
|
44
58
|
- lib/stoplight/color.rb
|
45
|
-
- lib/stoplight/
|
46
|
-
- lib/stoplight/
|
59
|
+
- lib/stoplight/config/config_provider.rb
|
60
|
+
- lib/stoplight/config/library_default_config.rb
|
61
|
+
- lib/stoplight/config/user_default_config.rb
|
47
62
|
- lib/stoplight/data_store.rb
|
48
63
|
- lib/stoplight/data_store/base.rb
|
64
|
+
- lib/stoplight/data_store/fail_safe.rb
|
49
65
|
- lib/stoplight/data_store/memory.rb
|
50
66
|
- lib/stoplight/data_store/redis.rb
|
67
|
+
- lib/stoplight/data_store/redis/get_metadata.lua
|
68
|
+
- lib/stoplight/data_store/redis/lua.rb
|
69
|
+
- lib/stoplight/data_store/redis/record_failure.lua
|
70
|
+
- lib/stoplight/data_store/redis/record_success.lua
|
71
|
+
- lib/stoplight/data_store/redis/transition_to_green.lua
|
72
|
+
- lib/stoplight/data_store/redis/transition_to_red.lua
|
73
|
+
- lib/stoplight/data_store/redis/transition_to_yellow.lua
|
51
74
|
- lib/stoplight/default.rb
|
52
75
|
- lib/stoplight/error.rb
|
53
76
|
- lib/stoplight/failure.rb
|
54
77
|
- lib/stoplight/light.rb
|
55
|
-
- lib/stoplight/light/
|
56
|
-
- lib/stoplight/light/
|
57
|
-
- lib/stoplight/light/
|
58
|
-
- lib/stoplight/
|
78
|
+
- lib/stoplight/light/config.rb
|
79
|
+
- lib/stoplight/light/configuration_builder_interface.rb
|
80
|
+
- lib/stoplight/light/green_run_strategy.rb
|
81
|
+
- lib/stoplight/light/red_run_strategy.rb
|
82
|
+
- lib/stoplight/light/run_strategy.rb
|
83
|
+
- lib/stoplight/light/yellow_run_strategy.rb
|
84
|
+
- lib/stoplight/metadata.rb
|
59
85
|
- lib/stoplight/notifier/base.rb
|
86
|
+
- lib/stoplight/notifier/fail_safe.rb
|
60
87
|
- lib/stoplight/notifier/generic.rb
|
61
88
|
- lib/stoplight/notifier/io.rb
|
62
89
|
- lib/stoplight/notifier/logger.rb
|
63
90
|
- lib/stoplight/rspec.rb
|
64
91
|
- lib/stoplight/rspec/generic_notifier.rb
|
65
92
|
- lib/stoplight/state.rb
|
93
|
+
- lib/stoplight/traffic_control/base.rb
|
94
|
+
- lib/stoplight/traffic_control/consecutive_failures.rb
|
95
|
+
- lib/stoplight/traffic_recovery/base.rb
|
96
|
+
- lib/stoplight/traffic_recovery/single_success.rb
|
66
97
|
- lib/stoplight/version.rb
|
67
|
-
- spec/spec_helper.rb
|
68
|
-
- spec/stoplight/builder_spec.rb
|
69
|
-
- spec/stoplight/circuit_breaker_spec.rb
|
70
|
-
- spec/stoplight/color_spec.rb
|
71
|
-
- spec/stoplight/configurable_spec.rb
|
72
|
-
- spec/stoplight/data_store/base_spec.rb
|
73
|
-
- spec/stoplight/data_store/memory_spec.rb
|
74
|
-
- spec/stoplight/data_store/redis_spec.rb
|
75
|
-
- spec/stoplight/data_store_spec.rb
|
76
|
-
- spec/stoplight/default_spec.rb
|
77
|
-
- spec/stoplight/error_spec.rb
|
78
|
-
- spec/stoplight/failure_spec.rb
|
79
|
-
- spec/stoplight/light/lockable_spec.rb
|
80
|
-
- spec/stoplight/light/runnable_spec.rb
|
81
|
-
- spec/stoplight/light_spec.rb
|
82
|
-
- spec/stoplight/notifier/base_spec.rb
|
83
|
-
- spec/stoplight/notifier/generic_spec.rb
|
84
|
-
- spec/stoplight/notifier/io_spec.rb
|
85
|
-
- spec/stoplight/notifier/logger_spec.rb
|
86
|
-
- spec/stoplight/notifier_spec.rb
|
87
|
-
- spec/stoplight/state_spec.rb
|
88
|
-
- spec/stoplight/version_spec.rb
|
89
|
-
- spec/stoplight_spec.rb
|
90
|
-
- spec/support/configurable.rb
|
91
|
-
- spec/support/data_store/base.rb
|
92
|
-
- spec/support/data_store/base/clear_failures.rb
|
93
|
-
- spec/support/data_store/base/clear_state.rb
|
94
|
-
- spec/support/data_store/base/get_all.rb
|
95
|
-
- spec/support/data_store/base/get_failures.rb
|
96
|
-
- spec/support/data_store/base/get_state.rb
|
97
|
-
- spec/support/data_store/base/names.rb
|
98
|
-
- spec/support/data_store/base/record_failures.rb
|
99
|
-
- spec/support/data_store/base/set_state.rb
|
100
|
-
- spec/support/data_store/base/with_notification_lock.rb
|
101
|
-
- spec/support/database_cleaner.rb
|
102
|
-
- spec/support/exception_helpers.rb
|
103
|
-
- spec/support/light/runnable.rb
|
104
|
-
- spec/support/light/runnable/color.rb
|
105
|
-
- spec/support/light/runnable/run.rb
|
106
|
-
- spec/support/light/runnable/state.rb
|
107
98
|
homepage: https://github.com/bolshakov/stoplight
|
108
99
|
licenses:
|
109
100
|
- MIT
|
@@ -116,55 +107,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
116
107
|
requirements:
|
117
108
|
- - ">="
|
118
109
|
- !ruby/object:Gem::Version
|
119
|
-
version: 3.
|
110
|
+
version: '3.2'
|
120
111
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
112
|
requirements:
|
122
113
|
- - ">="
|
123
114
|
- !ruby/object:Gem::Version
|
124
115
|
version: '0'
|
125
116
|
requirements: []
|
126
|
-
rubygems_version: 3.
|
117
|
+
rubygems_version: 3.4.19
|
127
118
|
signing_key:
|
128
119
|
specification_version: 4
|
129
120
|
summary: Traffic control for code.
|
130
|
-
test_files:
|
131
|
-
- spec/spec_helper.rb
|
132
|
-
- spec/stoplight/builder_spec.rb
|
133
|
-
- spec/stoplight/circuit_breaker_spec.rb
|
134
|
-
- spec/stoplight/color_spec.rb
|
135
|
-
- spec/stoplight/configurable_spec.rb
|
136
|
-
- spec/stoplight/data_store/base_spec.rb
|
137
|
-
- spec/stoplight/data_store/memory_spec.rb
|
138
|
-
- spec/stoplight/data_store/redis_spec.rb
|
139
|
-
- spec/stoplight/data_store_spec.rb
|
140
|
-
- spec/stoplight/default_spec.rb
|
141
|
-
- spec/stoplight/error_spec.rb
|
142
|
-
- spec/stoplight/failure_spec.rb
|
143
|
-
- spec/stoplight/light/lockable_spec.rb
|
144
|
-
- spec/stoplight/light/runnable_spec.rb
|
145
|
-
- spec/stoplight/light_spec.rb
|
146
|
-
- spec/stoplight/notifier/base_spec.rb
|
147
|
-
- spec/stoplight/notifier/generic_spec.rb
|
148
|
-
- spec/stoplight/notifier/io_spec.rb
|
149
|
-
- spec/stoplight/notifier/logger_spec.rb
|
150
|
-
- spec/stoplight/notifier_spec.rb
|
151
|
-
- spec/stoplight/state_spec.rb
|
152
|
-
- spec/stoplight/version_spec.rb
|
153
|
-
- spec/stoplight_spec.rb
|
154
|
-
- spec/support/configurable.rb
|
155
|
-
- spec/support/data_store/base/clear_failures.rb
|
156
|
-
- spec/support/data_store/base/clear_state.rb
|
157
|
-
- spec/support/data_store/base/get_all.rb
|
158
|
-
- spec/support/data_store/base/get_failures.rb
|
159
|
-
- spec/support/data_store/base/get_state.rb
|
160
|
-
- spec/support/data_store/base/names.rb
|
161
|
-
- spec/support/data_store/base/record_failures.rb
|
162
|
-
- spec/support/data_store/base/set_state.rb
|
163
|
-
- spec/support/data_store/base/with_notification_lock.rb
|
164
|
-
- spec/support/data_store/base.rb
|
165
|
-
- spec/support/database_cleaner.rb
|
166
|
-
- spec/support/exception_helpers.rb
|
167
|
-
- spec/support/light/runnable/color.rb
|
168
|
-
- spec/support/light/runnable/run.rb
|
169
|
-
- spec/support/light/runnable/state.rb
|
170
|
-
- spec/support/light/runnable.rb
|
121
|
+
test_files: []
|
data/lib/stoplight/builder.rb
DELETED
@@ -1,70 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'forwardable'
|
4
|
-
|
5
|
-
module Stoplight
|
6
|
-
# An interface to build Stoplight configuration. The builder is
|
7
|
-
# immutable, so it's safe to pass an instance of this builder
|
8
|
-
# across the code.
|
9
|
-
#
|
10
|
-
# @example
|
11
|
-
# circuit_breaker = Stoplight('http_api')
|
12
|
-
# .with_data_store(data_store)
|
13
|
-
# .with_cool_off_time(60)
|
14
|
-
# .with_threshold(5)
|
15
|
-
# .with_window_size(3600)
|
16
|
-
# .with_notifiers(notifiers)
|
17
|
-
# .with_error_notifier(error_notifier) #=> <#Stoplight::Builder ..>
|
18
|
-
#
|
19
|
-
# It's safe to pass this +circuit_breaker+ around your code like this:
|
20
|
-
#
|
21
|
-
# def call(circuit_breaker)
|
22
|
-
# circuit_breaker.run { call_api }
|
23
|
-
# end
|
24
|
-
#
|
25
|
-
# @api private use +Stoplight()+ method instead
|
26
|
-
class Builder
|
27
|
-
include CircuitBreaker
|
28
|
-
extend Forwardable
|
29
|
-
|
30
|
-
def_delegator :build, :with_error_handler
|
31
|
-
def_delegator :build, :with_fallback
|
32
|
-
def_delegator :build, :color
|
33
|
-
def_delegator :build, :name
|
34
|
-
def_delegator :build, :state
|
35
|
-
def_delegator :build, :run
|
36
|
-
def_delegator :build, :lock
|
37
|
-
def_delegator :build, :unlock
|
38
|
-
|
39
|
-
class << self
|
40
|
-
# @param settings [Hash]
|
41
|
-
# @see +Stoplight::Configuration#initialize+
|
42
|
-
# @return [Stoplight::Builder]
|
43
|
-
def with(**settings)
|
44
|
-
new Configuration.new(**settings)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
# @param [Stoplight::Configuration]
|
49
|
-
def initialize(configuration)
|
50
|
-
@configuration = configuration
|
51
|
-
end
|
52
|
-
|
53
|
-
# @return [Stoplight::Light]
|
54
|
-
def build(&code)
|
55
|
-
Light.new(configuration.name, configuration, &code)
|
56
|
-
end
|
57
|
-
|
58
|
-
# @param other [any]
|
59
|
-
# @return [Boolean]
|
60
|
-
def ==(other)
|
61
|
-
other.is_a?(self.class) && configuration == other.configuration
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
def reconfigure(configuration)
|
67
|
-
self.class.new(configuration)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
@@ -1,102 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Stoplight
|
4
|
-
# @abstract
|
5
|
-
module CircuitBreaker
|
6
|
-
include Configurable
|
7
|
-
|
8
|
-
# Configures a custom proc that allows you to not to handle an error
|
9
|
-
# with Stoplight.
|
10
|
-
#
|
11
|
-
# @example
|
12
|
-
# light = Stoplight('example')
|
13
|
-
# .with_error_handler do |error, handler|
|
14
|
-
# raise error if error.is_a?(ActiveRecord::RecordNotFound)
|
15
|
-
# handle.call(error)
|
16
|
-
# end
|
17
|
-
# light.run { User.find(123) }
|
18
|
-
#
|
19
|
-
# In the example above, the +ActiveRecord::RecordNotFound+ doesn't
|
20
|
-
# move the circuit breaker into the red state.
|
21
|
-
#
|
22
|
-
# @yieldparam error [Exception]
|
23
|
-
# @yieldparam handle [Proc]
|
24
|
-
# @return [Stoplight::CircuitBreaker]
|
25
|
-
def with_error_handler(&error_handler)
|
26
|
-
raise NotImplementedError
|
27
|
-
end
|
28
|
-
|
29
|
-
# Configures light with the given fallback block
|
30
|
-
#
|
31
|
-
# @example
|
32
|
-
# light = Stoplight('example')
|
33
|
-
# light.with_fallback { |error| e.is_a?()ZeroDivisionError) ? 0 : nil }
|
34
|
-
# light.run { 1 / 0} #=> 0
|
35
|
-
#
|
36
|
-
# @yieldparam error [Exception, nil]
|
37
|
-
# @return [Stoplight::CircuitBreaker]
|
38
|
-
def with_fallback(&fallback)
|
39
|
-
raise NotImplementedError
|
40
|
-
end
|
41
|
-
|
42
|
-
# @return [String] one of +locked_green+, +locked_red+, and +unlocked+
|
43
|
-
def state
|
44
|
-
raise NotImplementedError
|
45
|
-
end
|
46
|
-
|
47
|
-
# @return [String] the light's name
|
48
|
-
def name
|
49
|
-
raise NotImplementedError
|
50
|
-
end
|
51
|
-
|
52
|
-
# Returns current color:
|
53
|
-
# * +Stoplight::Color::GREEN+ -- circuit breaker is closed
|
54
|
-
# * +Stoplight::Color::RED+ -- circuit breaker is open
|
55
|
-
# * +Stoplight::Color::YELLOW+ -- circuit breaker is half-open
|
56
|
-
#
|
57
|
-
# @example
|
58
|
-
# light = Stoplight('example')
|
59
|
-
# light.color #=> Color::GREEN
|
60
|
-
#
|
61
|
-
# @return [String] returns current light color
|
62
|
-
def color
|
63
|
-
raise NotImplementedError
|
64
|
-
end
|
65
|
-
|
66
|
-
# Runs the given block of code with this circuit breaker
|
67
|
-
#
|
68
|
-
# @example
|
69
|
-
# light = Stoplight('example')
|
70
|
-
# light.run { 2/0 }
|
71
|
-
#
|
72
|
-
# @raise [Stoplight::Error::RedLight]
|
73
|
-
# @return [any]
|
74
|
-
def run(&code)
|
75
|
-
raise NotImplementedError
|
76
|
-
end
|
77
|
-
|
78
|
-
# Locks light in either +State::LOCKED_RED+ or +State::LOCKED_GREEN+
|
79
|
-
#
|
80
|
-
# @example
|
81
|
-
# light = Stoplight('example-locked')
|
82
|
-
# light.lock(Stoplight::Color::RED)
|
83
|
-
#
|
84
|
-
# @param color [String] should be either +Color::RED+ or +Color::GREEN+
|
85
|
-
# @return [Stoplight::CircuitBreaker] returns locked circuit breaker
|
86
|
-
def lock(color)
|
87
|
-
raise NotImplementedError
|
88
|
-
end
|
89
|
-
|
90
|
-
# Unlocks light and sets it's state to State::UNLOCKED
|
91
|
-
#
|
92
|
-
# @example
|
93
|
-
# light = Stoplight('example-locked')
|
94
|
-
# light.lock(Stoplight::Color::RED)
|
95
|
-
# light.unlock
|
96
|
-
#
|
97
|
-
# @return [Stoplight::CircuitBreaker] returns unlocked circuit breaker
|
98
|
-
def unlock
|
99
|
-
raise NotImplementedError
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|