stoplight 5.5.0 → 5.7.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 +4 -4
- data/README.md +1 -1
- data/lib/stoplight/admin/actions/remove.rb +23 -0
- data/lib/stoplight/admin/dependencies.rb +6 -1
- data/lib/stoplight/admin/helpers.rb +10 -5
- data/lib/stoplight/admin/lights_repository.rb +26 -14
- data/lib/stoplight/admin/views/_card.erb +13 -1
- data/lib/stoplight/admin.rb +9 -0
- data/lib/stoplight/common/deprecations.rb +11 -0
- data/lib/stoplight/domain/config.rb +5 -1
- data/lib/stoplight/domain/data_store.rb +58 -6
- data/lib/stoplight/domain/failure.rb +2 -0
- data/lib/stoplight/domain/light/configuration_builder_interface.rb +120 -16
- data/lib/stoplight/domain/light.rb +34 -24
- data/lib/stoplight/domain/metrics.rb +64 -0
- data/lib/stoplight/domain/recovery_lock_token.rb +15 -0
- data/lib/stoplight/domain/{metadata.rb → state_snapshot.rb} +29 -37
- data/lib/stoplight/domain/storage/metrics.rb +42 -0
- data/lib/stoplight/domain/storage/recovery_lock.rb +56 -0
- data/lib/stoplight/domain/storage/state.rb +87 -0
- data/lib/stoplight/domain/strategies/green_run_strategy.rb +2 -2
- data/lib/stoplight/domain/strategies/red_run_strategy.rb +3 -3
- data/lib/stoplight/domain/strategies/run_strategy.rb +2 -7
- data/lib/stoplight/domain/strategies/yellow_run_strategy.rb +63 -36
- data/lib/stoplight/domain/tracker/base.rb +0 -29
- data/lib/stoplight/domain/tracker/recovery_probe.rb +26 -22
- data/lib/stoplight/domain/tracker/request.rb +26 -21
- data/lib/stoplight/domain/traffic_control/base.rb +5 -5
- data/lib/stoplight/domain/traffic_control/consecutive_errors.rb +3 -7
- data/lib/stoplight/domain/traffic_control/error_rate.rb +3 -3
- data/lib/stoplight/domain/traffic_recovery/base.rb +5 -5
- data/lib/stoplight/domain/traffic_recovery/consecutive_successes.rb +4 -8
- data/lib/stoplight/domain/traffic_recovery.rb +0 -1
- data/lib/stoplight/infrastructure/data_store/fail_safe.rb +164 -0
- data/lib/stoplight/infrastructure/data_store/memory/metrics.rb +27 -0
- data/lib/stoplight/infrastructure/data_store/memory/recovery_lock_store.rb +54 -0
- data/lib/stoplight/infrastructure/data_store/memory/recovery_lock_token.rb +20 -0
- data/lib/stoplight/infrastructure/data_store/memory/state.rb +21 -0
- data/lib/stoplight/infrastructure/data_store/memory.rb +163 -132
- data/lib/stoplight/infrastructure/data_store/redis/lua_scripts/get_metrics.lua +26 -0
- data/lib/stoplight/infrastructure/data_store/redis/lua_scripts/record_recovery_probe_failure.lua +27 -0
- data/lib/stoplight/infrastructure/data_store/redis/lua_scripts/record_recovery_probe_success.lua +23 -0
- data/lib/stoplight/infrastructure/data_store/redis/lua_scripts/release_lock.lua +6 -0
- data/lib/stoplight/infrastructure/data_store/redis/recovery_lock_store.rb +73 -0
- data/lib/stoplight/infrastructure/data_store/redis/recovery_lock_token.rb +35 -0
- data/lib/stoplight/infrastructure/data_store/redis/scripting.rb +71 -0
- data/lib/stoplight/infrastructure/data_store/redis.rb +211 -165
- data/lib/stoplight/infrastructure/notifier/fail_safe.rb +62 -0
- data/lib/stoplight/infrastructure/storage/compatibility_metrics.rb +48 -0
- data/lib/stoplight/infrastructure/storage/compatibility_recovery_lock.rb +36 -0
- data/lib/stoplight/infrastructure/storage/compatibility_recovery_metrics.rb +55 -0
- data/lib/stoplight/infrastructure/storage/compatibility_state.rb +55 -0
- data/lib/stoplight/version.rb +1 -1
- data/lib/stoplight/wiring/data_store/base.rb +11 -0
- data/lib/stoplight/wiring/data_store/memory.rb +10 -0
- data/lib/stoplight/wiring/data_store/redis.rb +25 -0
- data/lib/stoplight/wiring/default.rb +1 -1
- data/lib/stoplight/wiring/default_configuration.rb +1 -1
- data/lib/stoplight/wiring/default_factory_builder.rb +1 -1
- data/lib/stoplight/wiring/light_builder.rb +185 -0
- data/lib/stoplight/wiring/light_factory/compatibility_validator.rb +55 -0
- data/lib/stoplight/wiring/light_factory/config_normalizer.rb +71 -0
- data/lib/stoplight/wiring/light_factory/configuration_pipeline.rb +72 -0
- data/lib/stoplight/wiring/light_factory/traffic_control_dsl.rb +26 -0
- data/lib/stoplight/wiring/light_factory/traffic_recovery_dsl.rb +21 -0
- data/lib/stoplight/wiring/light_factory.rb +45 -132
- data/lib/stoplight/wiring/notifier_factory.rb +26 -0
- data/lib/stoplight/wiring/public_api.rb +3 -2
- data/lib/stoplight.rb +18 -3
- metadata +55 -16
- data/lib/stoplight/infrastructure/data_store/redis/get_metadata.lua +0 -38
- data/lib/stoplight/infrastructure/data_store/redis/lua.rb +0 -25
- data/lib/stoplight/infrastructure/dependency_injection/container.rb +0 -249
- data/lib/stoplight/infrastructure/dependency_injection/unresolved_dependency_error.rb +0 -13
- data/lib/stoplight/wiring/container.rb +0 -80
- data/lib/stoplight/wiring/fail_safe_data_store.rb +0 -123
- data/lib/stoplight/wiring/fail_safe_notifier.rb +0 -79
- data/lib/stoplight/wiring/system_container.rb +0 -9
- data/lib/stoplight/wiring/system_light_factory.rb +0 -17
- /data/lib/stoplight/infrastructure/data_store/redis/{record_failure.lua → lua_scripts/record_failure.lua} +0 -0
- /data/lib/stoplight/infrastructure/data_store/redis/{record_success.lua → lua_scripts/record_success.lua} +0 -0
- /data/lib/stoplight/infrastructure/data_store/redis/{transition_to_green.lua → lua_scripts/transition_to_green.lua} +0 -0
- /data/lib/stoplight/infrastructure/data_store/redis/{transition_to_red.lua → lua_scripts/transition_to_red.lua} +0 -0
- /data/lib/stoplight/infrastructure/data_store/redis/{transition_to_yellow.lua → lua_scripts/transition_to_yellow.lua} +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stoplight
|
|
4
|
+
module Wiring
|
|
5
|
+
class LightFactory
|
|
6
|
+
TrafficControlDsl = proc do |value|
|
|
7
|
+
case value
|
|
8
|
+
in Domain::TrafficControl::Base
|
|
9
|
+
value
|
|
10
|
+
in :consecutive_errors
|
|
11
|
+
Domain::TrafficControl::ConsecutiveErrors.new
|
|
12
|
+
in :error_rate
|
|
13
|
+
Domain::TrafficControl::ErrorRate.new
|
|
14
|
+
in {error_rate: error_rate_settings}
|
|
15
|
+
Domain::TrafficControl::ErrorRate.new(**error_rate_settings)
|
|
16
|
+
else
|
|
17
|
+
raise Stoplight::Error::ConfigurationError, <<~ERROR
|
|
18
|
+
unsupported traffic_control strategy provided (`#{value}`). Supported options:
|
|
19
|
+
* :consecutive_errors
|
|
20
|
+
* :error_rate
|
|
21
|
+
ERROR
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stoplight
|
|
4
|
+
module Wiring
|
|
5
|
+
class LightFactory
|
|
6
|
+
TrafficRecoveryDsl = proc do |value|
|
|
7
|
+
case value
|
|
8
|
+
in Domain::TrafficRecovery::Base
|
|
9
|
+
value
|
|
10
|
+
in :consecutive_successes
|
|
11
|
+
Domain::TrafficRecovery::ConsecutiveSuccesses.new
|
|
12
|
+
else
|
|
13
|
+
raise Domain::Error::ConfigurationError, <<~ERROR
|
|
14
|
+
unsupported traffic_recovery strategy provided (`#{value}`). Supported options:
|
|
15
|
+
* :consecutive_successes
|
|
16
|
+
ERROR
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -15,15 +15,29 @@ module Stoplight
|
|
|
15
15
|
# @api private
|
|
16
16
|
|
|
17
17
|
class LightFactory < Domain::LightFactory
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
#
|
|
25
|
-
|
|
26
|
-
|
|
18
|
+
DEPENDENCY_KEYS = %i[data_store traffic_recovery traffic_control notifiers error_notifier].freeze
|
|
19
|
+
private_constant :DEPENDENCY_KEYS
|
|
20
|
+
|
|
21
|
+
CONFIG_KEYS = Domain::Config.members.freeze
|
|
22
|
+
private_constant :CONFIG_KEYS
|
|
23
|
+
|
|
24
|
+
# @!attribute [r] settings
|
|
25
|
+
# @return [Hash]
|
|
26
|
+
protected attr_reader :settings
|
|
27
|
+
|
|
28
|
+
def initialize(settings = {})
|
|
29
|
+
@settings = settings
|
|
30
|
+
|
|
31
|
+
validate_settings!
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private def validate_settings!
|
|
35
|
+
recognized = CONFIG_KEYS + DEPENDENCY_KEYS
|
|
36
|
+
unknown = settings.keys - recognized
|
|
37
|
+
|
|
38
|
+
return if unknown.empty?
|
|
39
|
+
|
|
40
|
+
raise ArgumentError, "Unknown settings: #{unknown.join(", ")}", caller(2)
|
|
27
41
|
end
|
|
28
42
|
|
|
29
43
|
# @param settings [Hash] Settings to override in the new factory
|
|
@@ -31,16 +45,7 @@ module Stoplight
|
|
|
31
45
|
# @return [Stoplight::Wiring::LightFactory]
|
|
32
46
|
# @see Stoplight()
|
|
33
47
|
def with(**settings)
|
|
34
|
-
|
|
35
|
-
config_settings = extract_config_settings(transformed_settings)
|
|
36
|
-
dependency_settings = extract_dependency_settings(transformed_settings)
|
|
37
|
-
|
|
38
|
-
validate_settings!(transformed_settings, config_settings, dependency_settings)
|
|
39
|
-
|
|
40
|
-
new_config = container.resolve(:config).with(**config_settings)
|
|
41
|
-
new_container = container.with(config: new_config, **dependency_settings)
|
|
42
|
-
|
|
43
|
-
self.class.new(new_container)
|
|
48
|
+
self.class.new(self.settings.merge(settings))
|
|
44
49
|
end
|
|
45
50
|
|
|
46
51
|
# Builds a fully-configured Light instance.
|
|
@@ -60,128 +65,36 @@ module Stoplight
|
|
|
60
65
|
# light.run { api_call }
|
|
61
66
|
|
|
62
67
|
def build
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
Stoplight::Domain::Light.new(
|
|
66
|
-
container.resolve(:config),
|
|
67
|
-
data_store: container.resolve(:data_store),
|
|
68
|
-
green_run_strategy: container.resolve(:green_run_strategy),
|
|
69
|
-
yellow_run_strategy: container.resolve(:yellow_run_strategy),
|
|
70
|
-
red_run_strategy: container.resolve(:red_run_strategy),
|
|
71
|
-
factory: self
|
|
72
|
-
)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def ==(other)
|
|
76
|
-
other.is_a?(self.class) && other.container == container
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
private def extract_config_settings(settings)
|
|
80
|
-
settings.slice(*container.resolve(:config).members)
|
|
81
|
-
end
|
|
68
|
+
config_settings = settings.slice(*CONFIG_KEYS)
|
|
69
|
+
dependency_settings = settings.slice(*DEPENDENCY_KEYS)
|
|
82
70
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
recognized_keys = config_settings.keys + dependency_settings.keys
|
|
89
|
-
unexpected_keys = settings.keys - recognized_keys
|
|
90
|
-
|
|
91
|
-
return if unexpected_keys.empty?
|
|
92
|
-
raise ArgumentError, "Unknown settings: #{unexpected_keys.join(", ")}"
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
private def transform_settings(settings)
|
|
96
|
-
settings.dup.tap do |transformed_settings|
|
|
97
|
-
transform_config_settings!(transformed_settings)
|
|
98
|
-
transform_dependencies_settings!(transformed_settings)
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
private def transform_config_settings!(settings)
|
|
103
|
-
if settings.key?(:tracked_errors)
|
|
104
|
-
settings[:tracked_errors] = normalize_array(settings[:tracked_errors])
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
if settings.key?(:skipped_errors)
|
|
108
|
-
settings[:skipped_errors] = normalize_array(settings[:skipped_errors])
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
if settings.key?(:cool_off_time)
|
|
112
|
-
settings[:cool_off_time] = normalize_cool_off_time(settings[:cool_off_time])
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
private def transform_dependencies_settings!(settings)
|
|
117
|
-
if settings.key?(:traffic_control)
|
|
118
|
-
settings[:traffic_control] = apply_traffic_control_dsl(settings[:traffic_control])
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
if settings.key?(:traffic_recovery)
|
|
122
|
-
settings[:traffic_recovery] = apply_traffic_recovery_dsl(settings[:traffic_recovery])
|
|
123
|
-
end
|
|
71
|
+
config, dependencies = ConfigurationPipeline.process(
|
|
72
|
+
config_settings,
|
|
73
|
+
dependency_settings
|
|
74
|
+
)
|
|
75
|
+
LightBuilder.new(factory: self, config:, **dependencies).build
|
|
124
76
|
end
|
|
125
77
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
case traffic_control
|
|
131
|
-
in Domain::TrafficControl::Base
|
|
132
|
-
traffic_control
|
|
133
|
-
in :consecutive_errors
|
|
134
|
-
Domain::TrafficControl::ConsecutiveErrors.new
|
|
135
|
-
in :error_rate
|
|
136
|
-
Domain::TrafficControl::ErrorRate.new
|
|
137
|
-
in {error_rate: error_rate_settings}
|
|
138
|
-
Domain::TrafficControl::ErrorRate.new(**error_rate_settings)
|
|
139
|
-
else
|
|
140
|
-
raise Domain::Error::ConfigurationError, <<~ERROR
|
|
141
|
-
unsupported traffic_control strategy provided (`#{traffic_control}`). Supported options:
|
|
142
|
-
* :consecutive_errors
|
|
143
|
-
* :error_rate
|
|
144
|
-
ERROR
|
|
145
|
-
end
|
|
146
|
-
end
|
|
78
|
+
# @return [Stoplight::Error::ConfigurationError]
|
|
79
|
+
def validate_configuration!
|
|
80
|
+
config_settings = settings.slice(*CONFIG_KEYS)
|
|
81
|
+
dependency_settings = settings.slice(*DEPENDENCY_KEYS)
|
|
147
82
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
Domain::TrafficRecovery::ConsecutiveSuccesses.new
|
|
154
|
-
else
|
|
155
|
-
raise Domain::Error::ConfigurationError, <<~ERROR
|
|
156
|
-
unsupported traffic_recovery strategy provided (`#{traffic_recovery}`). Supported options:
|
|
157
|
-
* :consecutive_successes
|
|
158
|
-
ERROR
|
|
159
|
-
end
|
|
83
|
+
ConfigurationPipeline.process(
|
|
84
|
+
config_settings,
|
|
85
|
+
dependency_settings
|
|
86
|
+
)
|
|
87
|
+
nil
|
|
160
88
|
end
|
|
161
89
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
validate_traffic_recovery!(container.resolve(:traffic_recovery), container.resolve(:config))
|
|
90
|
+
def ==(other)
|
|
91
|
+
other.is_a?(self.class) && other.settings == settings
|
|
165
92
|
end
|
|
166
93
|
|
|
167
|
-
|
|
168
|
-
traffic_control.check_compatibility(config).then do |compatibility_result|
|
|
169
|
-
if compatibility_result.incompatible?
|
|
170
|
-
raise Domain::Error::ConfigurationError.new(
|
|
171
|
-
"#{traffic_control.class.name} strategy is incompatible with the Stoplight configuration: #{compatibility_result.error_messages}"
|
|
172
|
-
)
|
|
173
|
-
end
|
|
174
|
-
end
|
|
175
|
-
end
|
|
94
|
+
alias_method :eql?, :==
|
|
176
95
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if compatibility_result.incompatible?
|
|
180
|
-
raise Domain::Error::ConfigurationError.new(
|
|
181
|
-
"#{traffic_recovery.class.name} strategy is incompatible with the Stoplight configuration: #{compatibility_result.error_messages}"
|
|
182
|
-
)
|
|
183
|
-
end
|
|
184
|
-
end
|
|
96
|
+
def hash
|
|
97
|
+
[self.class, settings].hash
|
|
185
98
|
end
|
|
186
99
|
end
|
|
187
100
|
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stoplight
|
|
4
|
+
module Wiring
|
|
5
|
+
class NotifierFactory
|
|
6
|
+
class << self
|
|
7
|
+
# Wraps a notifier with fail-safe mechanisms.
|
|
8
|
+
#
|
|
9
|
+
# @param notifier [Stoplight::Domain::StateTransitionNotifier] The notifier to wrap.
|
|
10
|
+
# @param error_notifier [Proc] called when wrapped data store fails
|
|
11
|
+
# @return [Stoplight::Notifier::FailSafe] The original notifier if it is already
|
|
12
|
+
# a +FailSafe+ instance, otherwise a new +FailSafe+ instance.
|
|
13
|
+
def create(notifier:, error_notifier:)
|
|
14
|
+
case notifier
|
|
15
|
+
in Infrastructure::Notifier::FailSafe if notifier.error_notifier == error_notifier
|
|
16
|
+
notifier
|
|
17
|
+
in Infrastructure::Notifier::FailSafe
|
|
18
|
+
Infrastructure::Notifier::FailSafe.new(notifier: notifier.notifier, error_notifier:)
|
|
19
|
+
else
|
|
20
|
+
Infrastructure::Notifier::FailSafe.new(notifier:, error_notifier:)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -12,8 +12,9 @@ module Stoplight
|
|
|
12
12
|
|
|
13
13
|
# Namespace aliases for data stores
|
|
14
14
|
module DataStore
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
Base = Stoplight::Wiring::DataStore::Base
|
|
16
|
+
Redis = Stoplight::Wiring::DataStore::Redis
|
|
17
|
+
Memory = Stoplight::Wiring::DataStore::Memory
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
# Namespace aliases for notifiers
|
data/lib/stoplight.rb
CHANGED
|
@@ -55,8 +55,10 @@ module Stoplight # rubocop:disable Style/Documentation
|
|
|
55
55
|
factory_builder = Wiring::DefaultFactoryBuilder.new
|
|
56
56
|
yield factory_builder.configuration if block_given?
|
|
57
57
|
|
|
58
|
+
default_light_factory = factory_builder.build
|
|
59
|
+
default_light_factory.validate_configuration!
|
|
58
60
|
@default_configuration = factory_builder.configuration
|
|
59
|
-
@default_light_factory =
|
|
61
|
+
@default_light_factory = default_light_factory
|
|
60
62
|
end
|
|
61
63
|
end
|
|
62
64
|
|
|
@@ -67,7 +69,7 @@ module Stoplight # rubocop:disable Style/Documentation
|
|
|
67
69
|
# @return [Stoplight::Light]
|
|
68
70
|
# @api private
|
|
69
71
|
def system_light(name, **settings)
|
|
70
|
-
Wiring::
|
|
72
|
+
Wiring::LightFactory.new.with(name: "__stoplight__#{name}", **settings).build
|
|
71
73
|
end
|
|
72
74
|
|
|
73
75
|
# Create a Light with the user default configuration.
|
|
@@ -121,7 +123,6 @@ end
|
|
|
121
123
|
# @param settings [Hash] Optional settings to configure the circuit breaker.
|
|
122
124
|
# @option settings [Numeric] :cool_off_time The time to wait before resetting the circuit breaker.
|
|
123
125
|
# @option settings [Stoplight::DataStore::Base] :data_store The data store to use for storing state.
|
|
124
|
-
# @option settings [Proc] :error_notifier A proc to handle error notifications.
|
|
125
126
|
# @option settings [Array<Stoplight::Notifier::Base>] :notifiers A list of notifiers to use.
|
|
126
127
|
# @option settings [Numeric] :threshold The failure threshold to trip the circuit breaker.
|
|
127
128
|
# @option settings [Numeric] :window_size The size of the rolling window for failure tracking.
|
|
@@ -161,5 +162,19 @@ end
|
|
|
161
162
|
# light = Stoplight("Payment API", traffic_control: :error_rate, threshold: 0.666, window_size: 300)
|
|
162
163
|
#
|
|
163
164
|
def Stoplight(name, **settings) # rubocop:disable Naming/MethodName
|
|
165
|
+
Stoplight::Common::Deprecations.deprecate(<<~MSG) if settings.include?(:error_notifier)
|
|
166
|
+
Passing "error_notifier" to Stoplight('#{name}') is deprecated and will be removed in v6.0.0.
|
|
167
|
+
|
|
168
|
+
IMPORTANT: The `error_notifier` is NOT called for exceptions in your protected code.
|
|
169
|
+
It only reports internal Stoplight failures (e.g., Redis connection errors).
|
|
170
|
+
|
|
171
|
+
To fix: Move `error_notifier` to global configuration:
|
|
172
|
+
|
|
173
|
+
Stoplight.configure do |config|
|
|
174
|
+
config.error_notifier = ->(error) { Logger.warn(error) }
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
See: https://github.com/bolshakov/stoplight#error-notifiers
|
|
178
|
+
MSG
|
|
164
179
|
Stoplight.light(name, **settings)
|
|
165
180
|
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: 5.
|
|
4
|
+
version: 5.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Cameron Desautels
|
|
@@ -25,6 +25,20 @@ dependencies:
|
|
|
25
25
|
- - ">="
|
|
26
26
|
- !ruby/object:Gem::Version
|
|
27
27
|
version: '0'
|
|
28
|
+
- !ruby/object:Gem::Dependency
|
|
29
|
+
name: concurrent-ruby
|
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
|
31
|
+
requirements:
|
|
32
|
+
- - ">="
|
|
33
|
+
- !ruby/object:Gem::Version
|
|
34
|
+
version: '0'
|
|
35
|
+
type: :runtime
|
|
36
|
+
prerelease: false
|
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
38
|
+
requirements:
|
|
39
|
+
- - ">="
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '0'
|
|
28
42
|
description: An implementation of the circuit breaker pattern.
|
|
29
43
|
email:
|
|
30
44
|
- camdez@gmail.com
|
|
@@ -47,6 +61,7 @@ files:
|
|
|
47
61
|
- lib/stoplight/admin/actions/lock_all_green.rb
|
|
48
62
|
- lib/stoplight/admin/actions/lock_green.rb
|
|
49
63
|
- lib/stoplight/admin/actions/lock_red.rb
|
|
64
|
+
- lib/stoplight/admin/actions/remove.rb
|
|
50
65
|
- lib/stoplight/admin/actions/stats.rb
|
|
51
66
|
- lib/stoplight/admin/actions/unlock.rb
|
|
52
67
|
- lib/stoplight/admin/dependencies.rb
|
|
@@ -57,6 +72,7 @@ files:
|
|
|
57
72
|
- lib/stoplight/admin/views/_card.erb
|
|
58
73
|
- lib/stoplight/admin/views/index.erb
|
|
59
74
|
- lib/stoplight/admin/views/layout.erb
|
|
75
|
+
- lib/stoplight/common/deprecations.rb
|
|
60
76
|
- lib/stoplight/domain/color.rb
|
|
61
77
|
- lib/stoplight/domain/compatibility_result.rb
|
|
62
78
|
- lib/stoplight/domain/config.rb
|
|
@@ -66,9 +82,14 @@ files:
|
|
|
66
82
|
- lib/stoplight/domain/light.rb
|
|
67
83
|
- lib/stoplight/domain/light/configuration_builder_interface.rb
|
|
68
84
|
- lib/stoplight/domain/light_factory.rb
|
|
69
|
-
- lib/stoplight/domain/
|
|
85
|
+
- lib/stoplight/domain/metrics.rb
|
|
86
|
+
- lib/stoplight/domain/recovery_lock_token.rb
|
|
70
87
|
- lib/stoplight/domain/state.rb
|
|
88
|
+
- lib/stoplight/domain/state_snapshot.rb
|
|
71
89
|
- lib/stoplight/domain/state_transition_notifier.rb
|
|
90
|
+
- lib/stoplight/domain/storage/metrics.rb
|
|
91
|
+
- lib/stoplight/domain/storage/recovery_lock.rb
|
|
92
|
+
- lib/stoplight/domain/storage/state.rb
|
|
72
93
|
- lib/stoplight/domain/strategies/green_run_strategy.rb
|
|
73
94
|
- lib/stoplight/domain/strategies/red_run_strategy.rb
|
|
74
95
|
- lib/stoplight/domain/strategies/run_strategy.rb
|
|
@@ -82,36 +103,54 @@ files:
|
|
|
82
103
|
- lib/stoplight/domain/traffic_recovery.rb
|
|
83
104
|
- lib/stoplight/domain/traffic_recovery/base.rb
|
|
84
105
|
- lib/stoplight/domain/traffic_recovery/consecutive_successes.rb
|
|
106
|
+
- lib/stoplight/infrastructure/data_store/fail_safe.rb
|
|
85
107
|
- lib/stoplight/infrastructure/data_store/memory.rb
|
|
108
|
+
- lib/stoplight/infrastructure/data_store/memory/metrics.rb
|
|
109
|
+
- lib/stoplight/infrastructure/data_store/memory/recovery_lock_store.rb
|
|
110
|
+
- lib/stoplight/infrastructure/data_store/memory/recovery_lock_token.rb
|
|
86
111
|
- lib/stoplight/infrastructure/data_store/memory/sliding_window.rb
|
|
112
|
+
- lib/stoplight/infrastructure/data_store/memory/state.rb
|
|
87
113
|
- lib/stoplight/infrastructure/data_store/redis.rb
|
|
88
|
-
- lib/stoplight/infrastructure/data_store/redis/
|
|
89
|
-
- lib/stoplight/infrastructure/data_store/redis/lua
|
|
90
|
-
- lib/stoplight/infrastructure/data_store/redis/
|
|
91
|
-
- lib/stoplight/infrastructure/data_store/redis/
|
|
92
|
-
- lib/stoplight/infrastructure/data_store/redis/
|
|
93
|
-
- lib/stoplight/infrastructure/data_store/redis/
|
|
94
|
-
- lib/stoplight/infrastructure/data_store/redis/
|
|
95
|
-
- lib/stoplight/infrastructure/
|
|
96
|
-
- lib/stoplight/infrastructure/
|
|
114
|
+
- lib/stoplight/infrastructure/data_store/redis/lua_scripts/get_metrics.lua
|
|
115
|
+
- lib/stoplight/infrastructure/data_store/redis/lua_scripts/record_failure.lua
|
|
116
|
+
- lib/stoplight/infrastructure/data_store/redis/lua_scripts/record_recovery_probe_failure.lua
|
|
117
|
+
- lib/stoplight/infrastructure/data_store/redis/lua_scripts/record_recovery_probe_success.lua
|
|
118
|
+
- lib/stoplight/infrastructure/data_store/redis/lua_scripts/record_success.lua
|
|
119
|
+
- lib/stoplight/infrastructure/data_store/redis/lua_scripts/release_lock.lua
|
|
120
|
+
- lib/stoplight/infrastructure/data_store/redis/lua_scripts/transition_to_green.lua
|
|
121
|
+
- lib/stoplight/infrastructure/data_store/redis/lua_scripts/transition_to_red.lua
|
|
122
|
+
- lib/stoplight/infrastructure/data_store/redis/lua_scripts/transition_to_yellow.lua
|
|
123
|
+
- lib/stoplight/infrastructure/data_store/redis/recovery_lock_store.rb
|
|
124
|
+
- lib/stoplight/infrastructure/data_store/redis/recovery_lock_token.rb
|
|
125
|
+
- lib/stoplight/infrastructure/data_store/redis/scripting.rb
|
|
126
|
+
- lib/stoplight/infrastructure/notifier/fail_safe.rb
|
|
97
127
|
- lib/stoplight/infrastructure/notifier/generic.rb
|
|
98
128
|
- lib/stoplight/infrastructure/notifier/io.rb
|
|
99
129
|
- lib/stoplight/infrastructure/notifier/logger.rb
|
|
130
|
+
- lib/stoplight/infrastructure/storage/compatibility_metrics.rb
|
|
131
|
+
- lib/stoplight/infrastructure/storage/compatibility_recovery_lock.rb
|
|
132
|
+
- lib/stoplight/infrastructure/storage/compatibility_recovery_metrics.rb
|
|
133
|
+
- lib/stoplight/infrastructure/storage/compatibility_state.rb
|
|
100
134
|
- lib/stoplight/rspec.rb
|
|
101
135
|
- lib/stoplight/rspec/generic_notifier.rb
|
|
102
136
|
- lib/stoplight/version.rb
|
|
103
|
-
- lib/stoplight/wiring/
|
|
137
|
+
- lib/stoplight/wiring/data_store/base.rb
|
|
138
|
+
- lib/stoplight/wiring/data_store/memory.rb
|
|
139
|
+
- lib/stoplight/wiring/data_store/redis.rb
|
|
104
140
|
- lib/stoplight/wiring/default.rb
|
|
105
141
|
- lib/stoplight/wiring/default_configuration.rb
|
|
106
142
|
- lib/stoplight/wiring/default_factory_builder.rb
|
|
107
|
-
- lib/stoplight/wiring/fail_safe_data_store.rb
|
|
108
|
-
- lib/stoplight/wiring/fail_safe_notifier.rb
|
|
109
143
|
- lib/stoplight/wiring/light/default_config.rb
|
|
110
144
|
- lib/stoplight/wiring/light/system_config.rb
|
|
145
|
+
- lib/stoplight/wiring/light_builder.rb
|
|
111
146
|
- lib/stoplight/wiring/light_factory.rb
|
|
147
|
+
- lib/stoplight/wiring/light_factory/compatibility_validator.rb
|
|
148
|
+
- lib/stoplight/wiring/light_factory/config_normalizer.rb
|
|
149
|
+
- lib/stoplight/wiring/light_factory/configuration_pipeline.rb
|
|
150
|
+
- lib/stoplight/wiring/light_factory/traffic_control_dsl.rb
|
|
151
|
+
- lib/stoplight/wiring/light_factory/traffic_recovery_dsl.rb
|
|
152
|
+
- lib/stoplight/wiring/notifier_factory.rb
|
|
112
153
|
- lib/stoplight/wiring/public_api.rb
|
|
113
|
-
- lib/stoplight/wiring/system_container.rb
|
|
114
|
-
- lib/stoplight/wiring/system_light_factory.rb
|
|
115
154
|
homepage: https://github.com/bolshakov/stoplight
|
|
116
155
|
licenses:
|
|
117
156
|
- MIT
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
local number_of_metric_buckets = tonumber(ARGV[1])
|
|
2
|
-
local number_of_recovery_buckets = tonumber(ARGV[2])
|
|
3
|
-
local window_start_ts = tonumber(ARGV[3])
|
|
4
|
-
local window_end_ts = tonumber(ARGV[4])
|
|
5
|
-
local recovery_window_start_ts = tonumber(ARGV[5])
|
|
6
|
-
|
|
7
|
-
local metadata_key = KEYS[1]
|
|
8
|
-
|
|
9
|
-
-- It possible that after a successful recovery, Stoplight still see metrics
|
|
10
|
-
-- that are older than the recovery window. To prevent this from happening,
|
|
11
|
-
-- we need to limit the start time of the window to the time of the last recovery.
|
|
12
|
-
local recovered_at = redis.call('HGET', metadata_key, "recovered_at")
|
|
13
|
-
if recovered_at then
|
|
14
|
-
window_start_ts = math.max(window_start_ts, tonumber(recovered_at))
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
local function count_events(start_idx, bucket_count, start_ts)
|
|
18
|
-
local total = 0
|
|
19
|
-
for idx = start_idx, start_idx + bucket_count - 1 do
|
|
20
|
-
total = total + tonumber(redis.call('ZCOUNT', KEYS[idx], start_ts, window_end_ts))
|
|
21
|
-
end
|
|
22
|
-
return total
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
local offset = 2
|
|
26
|
-
local successes = count_events(2, number_of_metric_buckets, window_start_ts)
|
|
27
|
-
|
|
28
|
-
offset = offset + number_of_metric_buckets
|
|
29
|
-
local errors = count_events(offset, number_of_metric_buckets, window_start_ts)
|
|
30
|
-
|
|
31
|
-
offset = offset + number_of_metric_buckets
|
|
32
|
-
local recovery_probe_successes = count_events(offset, number_of_recovery_buckets, recovery_window_start_ts)
|
|
33
|
-
|
|
34
|
-
offset = offset + number_of_recovery_buckets
|
|
35
|
-
local recovery_probe_errors = count_events(offset, number_of_recovery_buckets, recovery_window_start_ts)
|
|
36
|
-
|
|
37
|
-
local metadata = redis.call('HGETALL', metadata_key)
|
|
38
|
-
return {successes, errors, recovery_probe_successes, recovery_probe_errors, metadata}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Stoplight
|
|
4
|
-
module Infrastructure
|
|
5
|
-
module DataStore
|
|
6
|
-
class Redis
|
|
7
|
-
# @api private
|
|
8
|
-
module Lua
|
|
9
|
-
class << self
|
|
10
|
-
def read_lua_file(name_without_extension)
|
|
11
|
-
File.read(File.join(__dir__, "#{name_without_extension}.lua"))
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
RECORD_FAILURE = read_lua_file("record_failure")
|
|
16
|
-
RECORD_SUCCESS = read_lua_file("record_success")
|
|
17
|
-
GET_METADATA = read_lua_file("get_metadata")
|
|
18
|
-
TRANSITION_TO_YELLOW = read_lua_file("transition_to_yellow")
|
|
19
|
-
TRANSITION_TO_RED = read_lua_file("transition_to_red")
|
|
20
|
-
TRANSITION_TO_GREEN = read_lua_file("transition_to_green")
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|