stoplight 5.7.0 → 5.8.2
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/UPGRADING.md +303 -0
- data/lib/generators/stoplight/install/install_generator.rb +6 -1
- data/lib/stoplight/admin/dependencies.rb +1 -1
- data/lib/stoplight/admin/helpers.rb +20 -4
- data/lib/stoplight/admin/lights_repository/light.rb +22 -6
- data/lib/stoplight/admin/lights_repository.rb +6 -5
- data/lib/stoplight/admin/views/_card.erb +8 -5
- data/lib/stoplight/color.rb +9 -0
- data/lib/stoplight/data_store.rb +28 -0
- data/lib/stoplight/domain/compatibility_result.rb +7 -7
- data/lib/stoplight/domain/config.rb +38 -39
- data/lib/stoplight/domain/error_tracking_policy.rb +27 -0
- data/lib/stoplight/domain/failure.rb +1 -1
- data/lib/stoplight/domain/light/configuration_builder_interface.rb +2 -0
- data/lib/stoplight/domain/light.rb +15 -46
- data/lib/stoplight/domain/light_info.rb +7 -0
- data/lib/stoplight/domain/metrics_snapshot.rb +58 -0
- data/lib/stoplight/domain/state_snapshot.rb +29 -23
- data/lib/stoplight/domain/storage/recovery_lock_token.rb +15 -0
- data/lib/stoplight/domain/strategies/green_run_strategy.rb +18 -26
- data/lib/stoplight/domain/strategies/red_run_strategy.rb +9 -12
- data/lib/stoplight/domain/strategies/yellow_run_strategy.rb +41 -51
- data/lib/stoplight/domain/tracker/recovery_probe.rb +16 -33
- data/lib/stoplight/domain/tracker/request.rb +12 -31
- data/lib/stoplight/domain/traffic_control/consecutive_errors.rb +8 -11
- data/lib/stoplight/domain/traffic_control/error_rate.rb +19 -15
- data/lib/stoplight/domain/traffic_recovery/consecutive_successes.rb +6 -10
- data/lib/stoplight/domain/traffic_recovery.rb +3 -4
- data/lib/stoplight/error.rb +46 -0
- data/lib/stoplight/infrastructure/{data_store/fail_safe.rb → fail_safe/data_store.rb} +39 -51
- data/lib/stoplight/infrastructure/fail_safe/storage/metrics.rb +65 -0
- data/lib/stoplight/infrastructure/fail_safe/storage/recovery_lock.rb +69 -0
- data/lib/stoplight/infrastructure/fail_safe/storage/recovery_lock_token.rb +19 -0
- data/lib/stoplight/infrastructure/fail_safe/storage/state.rb +62 -0
- data/lib/stoplight/infrastructure/{data_store/memory → memory/data_store}/metrics.rb +2 -2
- data/lib/stoplight/infrastructure/{data_store/memory → memory/data_store}/recovery_lock_store.rb +10 -12
- data/lib/stoplight/infrastructure/{data_store/memory → memory/data_store}/recovery_lock_token.rb +3 -6
- data/lib/stoplight/infrastructure/{data_store/memory → memory/data_store}/sliding_window.rb +21 -26
- data/lib/stoplight/infrastructure/{data_store/memory → memory/data_store}/state.rb +3 -3
- data/lib/stoplight/infrastructure/{data_store/memory.rb → memory/data_store.rb} +36 -32
- data/lib/stoplight/infrastructure/memory/storage/recovery_lock.rb +35 -0
- data/lib/stoplight/infrastructure/memory/storage/recovery_metrics.rb +16 -0
- data/lib/stoplight/infrastructure/memory/storage/state.rb +155 -0
- data/lib/stoplight/infrastructure/memory/storage/unbounded_metrics.rb +103 -0
- data/lib/stoplight/infrastructure/memory/storage/window_metrics.rb +101 -0
- data/lib/stoplight/infrastructure/notifier/fail_safe.rb +9 -21
- data/lib/stoplight/infrastructure/notifier/generic.rb +4 -14
- data/lib/stoplight/infrastructure/notifier/io.rb +1 -2
- data/lib/stoplight/infrastructure/notifier/logger.rb +1 -2
- data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/recovery_lock_store.rb +9 -22
- data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/recovery_lock_token.rb +7 -14
- data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/scripting.rb +22 -20
- data/lib/stoplight/infrastructure/{data_store/redis.rb → redis/data_store.rb} +47 -55
- data/lib/stoplight/infrastructure/redis/storage/key_space.rb +51 -0
- data/lib/stoplight/infrastructure/redis/storage/metrics.rb +40 -0
- data/lib/stoplight/infrastructure/redis/storage/recovery_lock/release_lock.lua +6 -0
- data/lib/stoplight/infrastructure/redis/storage/recovery_lock.rb +64 -0
- data/lib/stoplight/infrastructure/redis/storage/recovery_metrics.rb +20 -0
- data/lib/stoplight/infrastructure/redis/storage/scripting.rb +18 -0
- data/lib/stoplight/infrastructure/redis/storage/state/transition_to_green.lua +10 -0
- data/lib/stoplight/infrastructure/redis/storage/state/transition_to_red.lua +10 -0
- data/lib/stoplight/infrastructure/redis/storage/state/transition_to_yellow.lua +9 -0
- data/lib/stoplight/infrastructure/redis/storage/state.rb +141 -0
- data/lib/stoplight/infrastructure/redis/storage/unbounded_metrics/record_failure.lua +28 -0
- data/lib/stoplight/infrastructure/redis/storage/unbounded_metrics/record_success.lua +26 -0
- data/lib/stoplight/infrastructure/redis/storage/unbounded_metrics.rb +123 -0
- data/lib/stoplight/infrastructure/redis/storage/window_metrics/metrics_snapshot.lua +26 -0
- data/lib/stoplight/infrastructure/redis/storage/window_metrics/record_failure.lua +36 -0
- data/lib/stoplight/infrastructure/redis/storage/window_metrics/record_success.lua +35 -0
- data/lib/stoplight/infrastructure/redis/storage/window_metrics.rb +174 -0
- data/lib/stoplight/infrastructure/storage/compatibility_metrics.rb +3 -10
- data/lib/stoplight/infrastructure/storage/compatibility_recovery_lock.rb +8 -11
- data/lib/stoplight/infrastructure/storage/compatibility_recovery_metrics.rb +6 -14
- data/lib/stoplight/infrastructure/storage/compatibility_state.rb +6 -17
- data/lib/stoplight/infrastructure/system_clock.rb +16 -0
- data/lib/stoplight/notifier.rb +11 -0
- data/lib/stoplight/state.rb +9 -0
- data/lib/stoplight/types.rb +29 -0
- data/lib/stoplight/undefined.rb +16 -0
- data/lib/stoplight/version.rb +1 -1
- data/lib/stoplight/wiring/config_compatibility_validator.rb +54 -0
- data/lib/stoplight/wiring/configuration_dsl.rb +101 -0
- data/lib/stoplight/wiring/data_store_backend.rb +26 -0
- data/lib/stoplight/wiring/default.rb +1 -1
- data/lib/stoplight/wiring/default_config.rb +21 -0
- data/lib/stoplight/wiring/default_configuration.rb +70 -53
- data/lib/stoplight/wiring/light_builder.rb +76 -63
- data/lib/stoplight/wiring/light_factory/traffic_control_dsl.rb +3 -3
- data/lib/stoplight/wiring/light_factory/traffic_recovery_dsl.rb +4 -4
- data/lib/stoplight/wiring/light_factory.rb +78 -52
- data/lib/stoplight/wiring/memory/backend.rb +57 -0
- data/lib/stoplight/wiring/redis/backend.rb +116 -0
- data/lib/stoplight/wiring/storage_set.rb +12 -0
- data/lib/stoplight/wiring/storage_set_builder.rb +51 -0
- data/lib/stoplight/wiring/system/light_builder.rb +47 -0
- data/lib/stoplight/wiring/system/light_factory.rb +64 -0
- data/lib/stoplight/wiring/system.rb +129 -0
- data/lib/stoplight.rb +196 -25
- data/sig/_private/generators/stoplight/install/install_generator.rbs +22 -0
- data/sig/_private/stoplight/common/deprecations.rbs +9 -0
- data/sig/_private/stoplight/data_store.rbs +6 -0
- data/sig/_private/stoplight/domain/compatibility_result.rbs +18 -0
- data/sig/_private/stoplight/domain/config.rbs +65 -0
- data/sig/_private/stoplight/domain/error_tracking_policy.rbs +14 -0
- data/sig/_private/stoplight/domain/failure.rbs +16 -0
- data/sig/_private/stoplight/domain/light.rbs +25 -0
- data/sig/_private/stoplight/domain/light_info.rbs +19 -0
- data/sig/_private/stoplight/domain/metrics_snapshot.rbs +38 -0
- data/sig/_private/stoplight/domain/ports/clock.rbs +18 -0
- data/sig/_private/stoplight/domain/ports/data_store.rbs +76 -0
- data/{lib/stoplight/domain/light_factory.rb → sig/_private/stoplight/domain/ports/light_factory.rbs} +33 -28
- data/sig/_private/stoplight/domain/ports/metrics_store.rbs +29 -0
- data/sig/_private/stoplight/domain/ports/recovery_lock_store.rbs +52 -0
- data/sig/_private/stoplight/domain/ports/recovery_lock_token.rbs +6 -0
- data/sig/_private/stoplight/domain/ports/run_strategy.rbs +14 -0
- data/sig/_private/stoplight/domain/ports/state_store.rbs +79 -0
- data/sig/_private/stoplight/domain/ports/traffic_control.rbs +41 -0
- data/sig/_private/stoplight/domain/ports/traffic_recovery.rbs +47 -0
- data/sig/_private/stoplight/domain/state_snapshot.rbs +32 -0
- data/sig/_private/stoplight/domain/storage/recovery_lock_token.rbs +11 -0
- data/sig/_private/stoplight/domain/strategies/green_run_strategy.rbs +17 -0
- data/sig/_private/stoplight/domain/strategies/red_run_strategy.rbs +17 -0
- data/sig/_private/stoplight/domain/strategies/yellow_run_strategy.rbs +42 -0
- data/{lib/stoplight/domain/tracker/base.rb → sig/_private/stoplight/domain/tracker/base.rbs} +0 -4
- data/sig/_private/stoplight/domain/tracker/recovery_probe.rbs +25 -0
- data/sig/_private/stoplight/domain/tracker/request.rbs +26 -0
- data/sig/_private/stoplight/domain/traffic_control/consecutive_errors.rbs +9 -0
- data/sig/_private/stoplight/domain/traffic_control/error_rate.rbs +13 -0
- data/sig/_private/stoplight/domain/traffic_recovery/consecutive_successes.rbs +9 -0
- data/sig/_private/stoplight/domain/traffic_recovery.rbs +9 -0
- data/sig/_private/stoplight/infrastructure/fail_safe/data_store.rbs +26 -0
- data/sig/_private/stoplight/infrastructure/fail_safe/storage/metrics.rbs +25 -0
- data/sig/_private/stoplight/infrastructure/fail_safe/storage/recovery_lock.rbs +29 -0
- data/sig/_private/stoplight/infrastructure/fail_safe/storage/recovery_lock_token.rbs +19 -0
- data/sig/_private/stoplight/infrastructure/fail_safe/storage/state.rbs +25 -0
- data/sig/_private/stoplight/infrastructure/memory/data_store/metrics.rbs +25 -0
- data/sig/_private/stoplight/infrastructure/memory/data_store/recovery_lock_store.rbs +19 -0
- data/sig/_private/stoplight/infrastructure/memory/data_store/recovery_lock_token.rbs +17 -0
- data/sig/_private/stoplight/infrastructure/memory/data_store/sliding_window.rbs +27 -0
- data/sig/_private/stoplight/infrastructure/memory/data_store/state.rbs +17 -0
- data/sig/_private/stoplight/infrastructure/memory/data_store.rbs +30 -0
- data/sig/_private/stoplight/infrastructure/memory/storage/recovery_lock.rbs +15 -0
- data/sig/_private/stoplight/infrastructure/memory/storage/recovery_metrics.rbs +10 -0
- data/sig/_private/stoplight/infrastructure/memory/storage/state.rbs +28 -0
- data/sig/_private/stoplight/infrastructure/memory/storage/unbounded_metrics.rbs +25 -0
- data/sig/_private/stoplight/infrastructure/memory/storage/window_metrics.rbs +26 -0
- data/sig/_private/stoplight/infrastructure/notifier/fail_safe.rbs +17 -0
- data/sig/_private/stoplight/infrastructure/notifier/generic.rbs +18 -0
- data/sig/_private/stoplight/infrastructure/notifier/io.rbs +14 -0
- data/sig/_private/stoplight/infrastructure/notifier/logger.rbs +14 -0
- data/sig/_private/stoplight/infrastructure/redis/data_store/recovery_lock_store.rbs +24 -0
- data/sig/_private/stoplight/infrastructure/redis/data_store/recovery_lock_token.rbs +21 -0
- data/sig/_private/stoplight/infrastructure/redis/data_store/scripting.rbs +34 -0
- data/sig/_private/stoplight/infrastructure/redis/data_store.rbs +67 -0
- data/sig/_private/stoplight/infrastructure/redis/storage/key_space.rbs +19 -0
- data/sig/_private/stoplight/infrastructure/redis/storage/metrics.rbs +17 -0
- data/sig/_private/stoplight/infrastructure/redis/storage/recovery_lock.rbs +26 -0
- data/sig/_private/stoplight/infrastructure/redis/storage/recovery_metrics.rbs +10 -0
- data/sig/_private/stoplight/infrastructure/redis/storage/scripting.rbs +13 -0
- data/sig/_private/stoplight/infrastructure/redis/storage/state.rbs +32 -0
- data/sig/_private/stoplight/infrastructure/redis/storage/unbounded_metrics.rbs +21 -0
- data/sig/_private/stoplight/infrastructure/redis/storage/window_metrics.rbs +34 -0
- data/sig/_private/stoplight/infrastructure/storage/compatibility_metrics.rbs +17 -0
- data/sig/_private/stoplight/infrastructure/storage/compatibility_recovery_lock.rbs +13 -0
- data/sig/_private/stoplight/infrastructure/storage/compatibility_recovery_metrics.rbs +14 -0
- data/sig/_private/stoplight/infrastructure/storage/compatibility_state.rbs +14 -0
- data/sig/_private/stoplight/infrastructure/system_clock.rbs +7 -0
- data/sig/_private/stoplight/system/light_builder.rbs +23 -0
- data/sig/_private/stoplight/system/light_factory.rbs +17 -0
- data/sig/_private/stoplight/types.rbs +6 -0
- data/sig/_private/stoplight/wiring/config_compatibility_validator.rbs +19 -0
- data/sig/_private/stoplight/wiring/configuration_dsl.rbs +43 -0
- data/sig/_private/stoplight/wiring/data_store_backend.rbs +11 -0
- data/sig/_private/stoplight/wiring/default.rbs +26 -0
- data/{lib/stoplight/wiring/data_store/memory.rb → sig/_private/stoplight/wiring/default_config.rbs} +1 -4
- data/sig/_private/stoplight/wiring/default_configuration.rbs +29 -0
- data/sig/_private/stoplight/wiring/light_builder.rbs +48 -0
- data/sig/_private/stoplight/wiring/light_factory/traffic_control_dsl.rbs +7 -0
- data/sig/_private/stoplight/wiring/light_factory/traffic_recovery_dsl.rbs +7 -0
- data/sig/_private/stoplight/wiring/light_factory.rbs +16 -0
- data/sig/_private/stoplight/wiring/memory/backend.rbs +26 -0
- data/sig/_private/stoplight/wiring/notifier_factory.rbs +10 -0
- data/sig/_private/stoplight/wiring/redis/backend.rbs +38 -0
- data/sig/_private/stoplight/wiring/storage_set.rbs +38 -0
- data/sig/_private/stoplight/wiring/storage_set_builder.rbs +15 -0
- data/sig/_private/stoplight/wiring/system.rbs +15 -0
- data/sig/_private/stoplight.rbs +48 -0
- data/sig/stoplight/color.rbs +7 -0
- data/sig/stoplight/data_store.rbs +19 -0
- data/sig/stoplight/error.rbs +20 -0
- data/sig/stoplight/notifier.rbs +11 -0
- data/sig/stoplight/ports/configuration.rbs +19 -0
- data/sig/stoplight/ports/exception_matcher.rbs +8 -0
- data/sig/stoplight/ports/light.rbs +12 -0
- data/sig/stoplight/ports/light_info.rbs +5 -0
- data/sig/stoplight/ports/state_transition_notifier.rbs +15 -0
- data/sig/stoplight/ports/system.rbs +21 -0
- data/sig/stoplight/state.rbs +7 -0
- data/sig/stoplight/undefined.rbs +9 -0
- data/sig/stoplight/version.rbs +3 -0
- data/sig/stoplight.rbs +66 -0
- metadata +175 -47
- data/lib/stoplight/domain/color.rb +0 -11
- data/lib/stoplight/domain/data_store.rb +0 -146
- data/lib/stoplight/domain/error.rb +0 -42
- data/lib/stoplight/domain/metrics.rb +0 -64
- data/lib/stoplight/domain/recovery_lock_token.rb +0 -15
- data/lib/stoplight/domain/state.rb +0 -11
- data/lib/stoplight/domain/state_transition_notifier.rb +0 -25
- data/lib/stoplight/domain/storage/metrics.rb +0 -42
- data/lib/stoplight/domain/storage/recovery_lock.rb +0 -56
- data/lib/stoplight/domain/storage/state.rb +0 -87
- data/lib/stoplight/domain/strategies/run_strategy.rb +0 -22
- data/lib/stoplight/domain/traffic_control/base.rb +0 -74
- data/lib/stoplight/domain/traffic_recovery/base.rb +0 -79
- data/lib/stoplight/wiring/data_store/base.rb +0 -11
- data/lib/stoplight/wiring/data_store/redis.rb +0 -25
- data/lib/stoplight/wiring/default_factory_builder.rb +0 -25
- data/lib/stoplight/wiring/light/default_config.rb +0 -18
- data/lib/stoplight/wiring/light/system_config.rb +0 -11
- data/lib/stoplight/wiring/light_factory/compatibility_validator.rb +0 -55
- data/lib/stoplight/wiring/light_factory/config_normalizer.rb +0 -71
- data/lib/stoplight/wiring/light_factory/configuration_pipeline.rb +0 -72
- data/lib/stoplight/wiring/public_api.rb +0 -29
- /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/get_metrics.lua +0 -0
- /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/record_failure.lua +0 -0
- /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/record_recovery_probe_failure.lua +0 -0
- /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/record_recovery_probe_success.lua +0 -0
- /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/record_success.lua +0 -0
- /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/release_lock.lua +0 -0
- /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/transition_to_green.lua +0 -0
- /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/transition_to_red.lua +0 -0
- /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/transition_to_yellow.lua +0 -0
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Stoplight
|
|
4
|
-
module Domain
|
|
5
|
-
module Error
|
|
6
|
-
Base = Class.new(StandardError)
|
|
7
|
-
ConfigurationError = Class.new(Base)
|
|
8
|
-
IncorrectColor = Class.new(Base)
|
|
9
|
-
|
|
10
|
-
class RedLight < Base
|
|
11
|
-
# @!attribute light_name
|
|
12
|
-
# @return [String] The light's name
|
|
13
|
-
attr_reader :light_name
|
|
14
|
-
|
|
15
|
-
# @!attribute cool_off_time
|
|
16
|
-
# @return [Numeric] Cool-off period in seconds
|
|
17
|
-
attr_reader :cool_off_time
|
|
18
|
-
|
|
19
|
-
# @!attribute retry_after
|
|
20
|
-
# @return [Time] Absolute Time after which a recovery attempt can occur
|
|
21
|
-
attr_reader :retry_after
|
|
22
|
-
|
|
23
|
-
# Initializes a new RedLight error.
|
|
24
|
-
#
|
|
25
|
-
# @param light_name [String] The light's name
|
|
26
|
-
#
|
|
27
|
-
# @option cool_off_time [Numeric] Cool-off period in seconds
|
|
28
|
-
#
|
|
29
|
-
# @option retry_after [Time] Absolute Time after which a recovery attempt can occur
|
|
30
|
-
#
|
|
31
|
-
# @return [Stoplight::Error::RedLight]
|
|
32
|
-
def initialize(light_name, cool_off_time:, retry_after:)
|
|
33
|
-
@light_name = light_name
|
|
34
|
-
@cool_off_time = cool_off_time
|
|
35
|
-
@retry_after = retry_after
|
|
36
|
-
|
|
37
|
-
super(light_name)
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Stoplight
|
|
4
|
-
module Domain
|
|
5
|
-
# Request metrics over a given window.
|
|
6
|
-
#
|
|
7
|
-
# @!attribute successes
|
|
8
|
-
# A number of successes withing requested window. Zero for non-windowed metrics
|
|
9
|
-
# @return [Integer]
|
|
10
|
-
#
|
|
11
|
-
# @!attribute errors
|
|
12
|
-
# A number of errors withing requested window. Zero for non-windowed metrics
|
|
13
|
-
# @return [Integer]
|
|
14
|
-
#
|
|
15
|
-
# @!attribute consecutive_errors
|
|
16
|
-
# A number of consecutive errors
|
|
17
|
-
# @return [Integer]
|
|
18
|
-
#
|
|
19
|
-
# @!attribute consecutive_successes
|
|
20
|
-
# A number of consecutive successes
|
|
21
|
-
# @return [Integer]
|
|
22
|
-
#
|
|
23
|
-
# @!attribute last_error
|
|
24
|
-
# @return [Stoplight::Domain::Failure, nil]
|
|
25
|
-
#
|
|
26
|
-
# @!attribute last_success_at
|
|
27
|
-
# @return [Time, nil]
|
|
28
|
-
#
|
|
29
|
-
# @api private
|
|
30
|
-
Metrics = Data.define(
|
|
31
|
-
:successes,
|
|
32
|
-
:errors,
|
|
33
|
-
:consecutive_errors,
|
|
34
|
-
:consecutive_successes,
|
|
35
|
-
:last_error,
|
|
36
|
-
:last_success_at
|
|
37
|
-
) do
|
|
38
|
-
# Calculates the error rate based on the number of successes and errors.
|
|
39
|
-
#
|
|
40
|
-
# @return [Float]
|
|
41
|
-
def error_rate
|
|
42
|
-
return unless requests # we effectively check if this is windowed metrics
|
|
43
|
-
|
|
44
|
-
if (successes + errors).zero?
|
|
45
|
-
0.0
|
|
46
|
-
else
|
|
47
|
-
errors.fdiv(successes + errors)
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# @return [Integer]
|
|
52
|
-
def requests
|
|
53
|
-
if successes && errors # we effectively check if this is windowed metrics
|
|
54
|
-
successes + errors
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# @return [Time, nil]
|
|
59
|
-
def last_error_at
|
|
60
|
-
last_error&.time
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Stoplight
|
|
4
|
-
module Domain
|
|
5
|
-
# Token representing an acquired recovery lock.
|
|
6
|
-
#
|
|
7
|
-
# Returned by +DataStore#acquire_recovery_lock+ and passed to
|
|
8
|
-
# +DataStore#release_recovery_lock+ to identify which lock to release.
|
|
9
|
-
#
|
|
10
|
-
# The actual locking mechanism lives in DataStore implementations,
|
|
11
|
-
# not in these tokens.
|
|
12
|
-
class RecoveryLockToken
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Stoplight
|
|
4
|
-
module Domain
|
|
5
|
-
# Base class for creating custom notifiers in Stoplight.
|
|
6
|
-
# This is an abstract class that defines the interface for notifiers.
|
|
7
|
-
#
|
|
8
|
-
# @abstract Subclasses must implement the `notify` method to define custom notification logic.
|
|
9
|
-
# :nocov:
|
|
10
|
-
class StateTransitionNotifier # ColorTransition?????
|
|
11
|
-
# Sends a notification when a Stoplight changes state.
|
|
12
|
-
#
|
|
13
|
-
# @param config [Stoplight::Domain::Config] The Stoplight instance triggering the notification.
|
|
14
|
-
# @param from_color [String] The previous state color of the Stoplight.
|
|
15
|
-
# @param to_color [String] The new state color of the Stoplight.
|
|
16
|
-
# @param error [Exception, nil] The error (if any) that caused the state change.
|
|
17
|
-
# @return [String] The result of the notification process.
|
|
18
|
-
#
|
|
19
|
-
def notify(config, from_color, to_color, error)
|
|
20
|
-
raise NotImplementedError
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
# :nocov:
|
|
24
|
-
end
|
|
25
|
-
end
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Stoplight
|
|
4
|
-
module Domain
|
|
5
|
-
module Storage
|
|
6
|
-
# Encapsulates metrics storage for circuit breaker execution tracking.
|
|
7
|
-
#
|
|
8
|
-
# This abstraction isolates metrics collection and retrieval from the
|
|
9
|
-
# broader data store concerns, enabling:
|
|
10
|
-
# - Purpose-built implementations optimized for time-series data
|
|
11
|
-
# - Independent scaling and optimization of metrics vs. state storage
|
|
12
|
-
# - Clearer separation between "what happened" (metrics) and "what to do" (state)
|
|
13
|
-
#
|
|
14
|
-
# Lifecycle: A Metrics instance is scoped to a single circuit breaker
|
|
15
|
-
# configuration. Each circuit gets its own metrics store instance,
|
|
16
|
-
# allowing different circuits to use different storage strategies.
|
|
17
|
-
#
|
|
18
|
-
# @abstract
|
|
19
|
-
class Metrics
|
|
20
|
-
# Retrieves a snapshot of current metrics for decision-making.
|
|
21
|
-
#
|
|
22
|
-
# @return [Stoplight::Domain::Metrics]
|
|
23
|
-
def metrics_snapshot = raise NotImplementedError
|
|
24
|
-
|
|
25
|
-
# Records a successful circuit breaker execution
|
|
26
|
-
#
|
|
27
|
-
# @return [void]
|
|
28
|
-
def record_success = raise NotImplementedError
|
|
29
|
-
|
|
30
|
-
# Records a failed circuit breaker execution
|
|
31
|
-
#
|
|
32
|
-
# @param error [StandardError]
|
|
33
|
-
# @return [void]
|
|
34
|
-
def record_failure(error) = raise NotImplementedError
|
|
35
|
-
|
|
36
|
-
# Clears all metrics for this circuit
|
|
37
|
-
# @return [void]
|
|
38
|
-
def clear = raise NotImplementedError
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Stoplight
|
|
4
|
-
module Domain
|
|
5
|
-
module Storage
|
|
6
|
-
# Encapsulates recovery lock management for coordinating recovery probes.
|
|
7
|
-
#
|
|
8
|
-
# When a circuit enters YELLOW state (half-open), it begins sending
|
|
9
|
-
# "recovery probes" - test requests to check if the protected service
|
|
10
|
-
# has recovered. In distributed deployments with multiple instances,
|
|
11
|
-
# recovery locks ensure only ONE instance sends probes at a time.
|
|
12
|
-
#
|
|
13
|
-
# Without coordination, all instances would simultaneously:
|
|
14
|
-
# 1. Detect the circuit is YELLOW
|
|
15
|
-
# 2. Send recovery probes to the struggling service
|
|
16
|
-
# 3. Potentially overwhelm it with "test" traffic
|
|
17
|
-
#
|
|
18
|
-
# Lock Lifecycle:
|
|
19
|
-
#
|
|
20
|
-
# Instance A: acquire_lock -> probe -> release_lock
|
|
21
|
-
# Instance B: acquire_lock -> nil (already held) -> skip probe
|
|
22
|
-
# Instance C: acquire_lock -> nil (already held) -> skip probe
|
|
23
|
-
#
|
|
24
|
-
# Lock Semantics:
|
|
25
|
-
# - Returns +nil+ if lock is already held. Never blocks waiting for lock availability
|
|
26
|
-
# - Locks must automatically expire when persisted storage is used
|
|
27
|
-
# - Failed releases are acceptable (timeout provides safety)
|
|
28
|
-
#
|
|
29
|
-
# @abstract
|
|
30
|
-
# @see Stoplight::Domain::Strategies::YellowRunStrategy
|
|
31
|
-
class RecoveryLock
|
|
32
|
-
# Attempts to acquire recovery lock for exclusive probe execution.
|
|
33
|
-
#
|
|
34
|
-
# This method tries to acquire a lock that serializes recovery probe
|
|
35
|
-
# execution across multiple instances. If the lock is already held by
|
|
36
|
-
# another instance, returns +nil+ immediately without blocking.
|
|
37
|
-
#
|
|
38
|
-
# @return [Stoplight::Domain::RecoveryLockToken, nil]
|
|
39
|
-
# - +RecoveryLockToken+: Lock acquired, caller should send probe
|
|
40
|
-
# - +nil+: Lock unavailable, another instance is probing
|
|
41
|
-
#
|
|
42
|
-
def acquire_lock = raise NotImplementedError
|
|
43
|
-
|
|
44
|
-
# Releases a previously acquired lock.
|
|
45
|
-
#
|
|
46
|
-
# This method releases the lock token returned by +#acquire_lock+,
|
|
47
|
-
# allowing other instances to acquire it. Release should be called
|
|
48
|
-
# in an ensure block to guarantee cleanup even if probe fails.
|
|
49
|
-
#
|
|
50
|
-
# @param lock [Stoplight::Domain::RecoveryLockToken] The token returned by +#acquire_lock+
|
|
51
|
-
# @return [void]
|
|
52
|
-
def release_lock(lock) = raise NotImplementedError
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Stoplight
|
|
4
|
-
module Domain
|
|
5
|
-
module Storage
|
|
6
|
-
# Encapsulates circuit breaker state storage.
|
|
7
|
-
#
|
|
8
|
-
# State management handles the current operational mode of a circuit breaker:
|
|
9
|
-
# - Color (GREEN/YELLOW/RED) - whether the circuit is open or closed
|
|
10
|
-
# - Lock state (LOCKED_GREEN/LOCKED_RED/UNLOCKED) - manual overrides
|
|
11
|
-
# - State transitions - tracking color changes for notifications #
|
|
12
|
-
#
|
|
13
|
-
# State requires stronger consistency than metrics because:
|
|
14
|
-
# - Multiple instances must agree on circuit color
|
|
15
|
-
# - Race conditions during transitions must be handled
|
|
16
|
-
# - Lock states must be immediately visible across instances
|
|
17
|
-
#
|
|
18
|
-
# @abstract
|
|
19
|
-
# @see Stoplight::Domain::Storage::Metrics
|
|
20
|
-
class State
|
|
21
|
-
# Retrieves current state snapshot for decision-making.
|
|
22
|
-
#
|
|
23
|
-
# The snapshot is an immutable view of the circuit's current state,
|
|
24
|
-
# including its color and lock status. This method is called on every
|
|
25
|
-
# circuit breaker invocation to determine whether to allow traffic.
|
|
26
|
-
#
|
|
27
|
-
# This is called on every request, so implementations should be fast.
|
|
28
|
-
#
|
|
29
|
-
# @return [Stoplight::Domain::StateSnapshot]
|
|
30
|
-
def state_snapshot = raise NotImplementedError
|
|
31
|
-
|
|
32
|
-
# Sets the lock state of the circuit.
|
|
33
|
-
#
|
|
34
|
-
# Locks allow manual override of circuit behavior:
|
|
35
|
-
# - LOCKED_GREEN: Force circuit closed (allow all traffic)
|
|
36
|
-
# - LOCKED_RED: Force circuit open (block all traffic)
|
|
37
|
-
# - UNLOCKED: Follow normal circuit breaker rules
|
|
38
|
-
#
|
|
39
|
-
# Lock states take precedence over color states. A locked circuit
|
|
40
|
-
# ignores failure thresholds and stays in the locked state until
|
|
41
|
-
# explicitly unlocked.
|
|
42
|
-
#
|
|
43
|
-
# Use Cases:
|
|
44
|
-
# - Emergency traffic control during incidents
|
|
45
|
-
# - Maintenance windows (lock RED to prevent traffic)
|
|
46
|
-
# - Gradual rollout (lock GREEN during testing)
|
|
47
|
-
#
|
|
48
|
-
# @param state [String] The new state to set.
|
|
49
|
-
# @return [String] The state that was set.
|
|
50
|
-
def set_state(state) = raise NotImplementedError
|
|
51
|
-
|
|
52
|
-
# Transitions the Stoplight to the specified color.
|
|
53
|
-
#
|
|
54
|
-
# This method performs a color transition operation that works across distributed instances
|
|
55
|
-
# of the light. It ensures that in a multi-instance environment, only one instance
|
|
56
|
-
# is considered the "first" to perform the transition (and therefore responsible for
|
|
57
|
-
# triggering notifications).
|
|
58
|
-
#
|
|
59
|
-
# @param color [String] The target color/state to transition to.
|
|
60
|
-
# Should be one of Stoplight::Color::GREEN, Stoplight::Color::YELLOW, or Stoplight::Color::RED.
|
|
61
|
-
#
|
|
62
|
-
# @return [Boolean] Returns +true+ if this instance was the first to perform this specific transition
|
|
63
|
-
# (and should therefore trigger notifications). Returns +false+ if another instance already
|
|
64
|
-
# initiated this transition.
|
|
65
|
-
#
|
|
66
|
-
# @note In distributed environments with multiple instances, race conditions can occur when instances
|
|
67
|
-
# attempt conflicting transitions simultaneously (e.g., one instance tries to transition from
|
|
68
|
-
# YELLOW to GREEN while another tries YELLOW to RED). The implementation handles this, but
|
|
69
|
-
# be aware that the last operation may determine the final color of the light.
|
|
70
|
-
#
|
|
71
|
-
def transition_to_color(color) = raise NotImplementedError
|
|
72
|
-
|
|
73
|
-
# Clears all state data for this circuit.
|
|
74
|
-
#
|
|
75
|
-
# This removes the circuit from storage entirely, resetting it to
|
|
76
|
-
# default (unlocked, green) state. The next invocation will start
|
|
77
|
-
# with fresh state.
|
|
78
|
-
#
|
|
79
|
-
# @note This does NOT clear metrics. If you want to fully
|
|
80
|
-
# reset a circuit, clear both state and metrics stores.
|
|
81
|
-
#
|
|
82
|
-
# @return [void]
|
|
83
|
-
def clear = raise NotImplementedError
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Stoplight
|
|
4
|
-
module Domain
|
|
5
|
-
module Strategies
|
|
6
|
-
# Represents an abstract strategy for running a light's operations.
|
|
7
|
-
# Every new strategy should be a child of this class.
|
|
8
|
-
#
|
|
9
|
-
# @api private
|
|
10
|
-
# @abstract
|
|
11
|
-
class RunStrategy
|
|
12
|
-
# @param fallback [Proc, nil] A fallback proc to execute in case of an error.
|
|
13
|
-
# @param state_snapshot [Stoplight::Domain::StateSnapshot]
|
|
14
|
-
# :nocov:
|
|
15
|
-
def execute(fallback, state_snapshot:, &code)
|
|
16
|
-
raise NotImplementedError, "Subclasses must implement the execute method"
|
|
17
|
-
end
|
|
18
|
-
# :nocov:
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Stoplight
|
|
4
|
-
module Domain
|
|
5
|
-
module TrafficControl
|
|
6
|
-
# Strategies for determining when a Stoplight should change color to red.
|
|
7
|
-
#
|
|
8
|
-
# These strategies evaluate the current state and metrics of a Stoplight to decide
|
|
9
|
-
# if traffic should be stopped (i.e., if the light should turn RED).
|
|
10
|
-
#
|
|
11
|
-
# @example Creating a custom strategy
|
|
12
|
-
# class ErrorRateStrategy < Stoplight::Domain::TrafficControl::Base
|
|
13
|
-
# def check_compatibility(config)
|
|
14
|
-
# if config.window_size.nil?
|
|
15
|
-
# incompatible("`window_size` should be set")
|
|
16
|
-
# else
|
|
17
|
-
# compatible
|
|
18
|
-
# end
|
|
19
|
-
# end
|
|
20
|
-
#
|
|
21
|
-
# def stop_traffic?(config, metrics)
|
|
22
|
-
# total = metrics.successes + metrics.failures
|
|
23
|
-
# return false if total < 10 # Minimum sample size
|
|
24
|
-
#
|
|
25
|
-
# error_rate = metrics.failures.fdiv(total)
|
|
26
|
-
# error_rate >= 0.5 # Stop traffic when error rate reaches 50%
|
|
27
|
-
# end
|
|
28
|
-
# end
|
|
29
|
-
#
|
|
30
|
-
# @abstract
|
|
31
|
-
# @api private
|
|
32
|
-
class Base
|
|
33
|
-
# Checks if the strategy is compatible with the given Stoplight configuration.
|
|
34
|
-
#
|
|
35
|
-
# @param config [Stoplight::Domain::Config]
|
|
36
|
-
# @return [Stoplight::Domain::CompatibilityResult]
|
|
37
|
-
# :nocov:
|
|
38
|
-
def check_compatibility(config)
|
|
39
|
-
raise NotImplementedError
|
|
40
|
-
end
|
|
41
|
-
# :nocov:
|
|
42
|
-
|
|
43
|
-
# Determines whether traffic should be stopped based on the Stoplight's
|
|
44
|
-
# current state and metrics.
|
|
45
|
-
#
|
|
46
|
-
# @param config [Stoplight::Domain::Config]
|
|
47
|
-
# @param metrics [Stoplight::Domain::Metrics]
|
|
48
|
-
# @return [Boolean] true if traffic should be stopped (rec), false otherwise (green)
|
|
49
|
-
# :nocov:
|
|
50
|
-
def stop_traffic?(config, metrics)
|
|
51
|
-
raise NotImplementedError
|
|
52
|
-
end
|
|
53
|
-
# :nocov:
|
|
54
|
-
|
|
55
|
-
# @param other [any]
|
|
56
|
-
# @return [Boolean]
|
|
57
|
-
def ==(other)
|
|
58
|
-
other.is_a?(self.class)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Returns a compatibility result indicating the strategy is compatible.
|
|
62
|
-
#
|
|
63
|
-
# @return [Stoplight::Domain::CompatibilityResult] A compatible result.
|
|
64
|
-
private def compatible = CompatibilityResult.compatible
|
|
65
|
-
|
|
66
|
-
# Returns a compatibility result indicating the strategy is incompatible.
|
|
67
|
-
#
|
|
68
|
-
# @param errors [Array<String>] The list of error messages describing incompatibility.
|
|
69
|
-
# @return [Stoplight::Domain::CompatibilityResult] An incompatible result.
|
|
70
|
-
private def incompatible(*errors) = CompatibilityResult.incompatible(*errors)
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
end
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Stoplight
|
|
4
|
-
module Domain
|
|
5
|
-
module TrafficRecovery
|
|
6
|
-
# Strategies for determining how to recover traffic flow through the Stoplight.
|
|
7
|
-
# These strategies evaluate recovery metrics to decide which color the Stoplight should
|
|
8
|
-
# transition to during the recovery process.
|
|
9
|
-
#
|
|
10
|
-
# @example Creating a custom traffic recovery strategy
|
|
11
|
-
# class GradualRecovery < Stoplight::Domain::TrafficRecovery::Base
|
|
12
|
-
# def initialize(min_success_rate: 0.8, min_samples: 100)
|
|
13
|
-
# @min_success_rate = min_success_rate
|
|
14
|
-
# @min_samples = min_samples
|
|
15
|
-
# end
|
|
16
|
-
#
|
|
17
|
-
# def determine_color(config, metrics)
|
|
18
|
-
# total_probes = metrics.recovery_probe_successes + metrics.recovery_probe_errors
|
|
19
|
-
#
|
|
20
|
-
# if total_probes < @min_samples
|
|
21
|
-
# return Color::YELLOW # Keep recovering, not enough samples
|
|
22
|
-
# end
|
|
23
|
-
#
|
|
24
|
-
# success_rate = metrics.recovery_probe_successes.fdiv(total_probes)
|
|
25
|
-
# if success_rate >= @min_success_rate
|
|
26
|
-
# Color::GREEN # Recovery successful
|
|
27
|
-
# elsif success_rate <= 0.2
|
|
28
|
-
# Color::RED # Recovery failed, too many errors
|
|
29
|
-
# else
|
|
30
|
-
# Color::YELLOW # Continue recovery
|
|
31
|
-
# end
|
|
32
|
-
# end
|
|
33
|
-
# end
|
|
34
|
-
#
|
|
35
|
-
# @abstract
|
|
36
|
-
# @api private
|
|
37
|
-
class Base
|
|
38
|
-
# Checks if the strategy is compatible with the given Stoplight configuration.
|
|
39
|
-
#
|
|
40
|
-
# @param config [Stoplight::Domain::Config]
|
|
41
|
-
# @return [Stoplight::Domain::CompatibilityResult]
|
|
42
|
-
# :nocov:
|
|
43
|
-
def check_compatibility(config)
|
|
44
|
-
raise NotImplementedError
|
|
45
|
-
end
|
|
46
|
-
# :nocov:
|
|
47
|
-
|
|
48
|
-
# Determines the appropriate recovery state based on the Stoplight's
|
|
49
|
-
# current metrics and recovery progress.
|
|
50
|
-
#
|
|
51
|
-
# @param config [Stoplight::Domain::Config]
|
|
52
|
-
# @param metrics [Stoplight::Domain::Metrics]
|
|
53
|
-
# @return [TrafficRecovery::Decision]
|
|
54
|
-
# :nocov:
|
|
55
|
-
def determine_color(config, metrics)
|
|
56
|
-
raise NotImplementedError
|
|
57
|
-
end
|
|
58
|
-
# :nocov:
|
|
59
|
-
|
|
60
|
-
# @param other [any]
|
|
61
|
-
# @return [Boolean]
|
|
62
|
-
def ==(other)
|
|
63
|
-
other.is_a?(self.class)
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# Returns a compatibility result indicating the strategy is compatible.
|
|
67
|
-
#
|
|
68
|
-
# @return [Stoplight::Domain::CompatibilityResult] A compatible result.
|
|
69
|
-
private def compatible = CompatibilityResult.compatible
|
|
70
|
-
|
|
71
|
-
# Returns a compatibility result indicating the strategy is incompatible.
|
|
72
|
-
#
|
|
73
|
-
# @param errors [Array<String>] The list of error messages describing incompatibility.
|
|
74
|
-
# @return [Stoplight::Domain::CompatibilityResult] An incompatible result.
|
|
75
|
-
private def incompatible(*errors) = CompatibilityResult.incompatible(*errors)
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Stoplight
|
|
4
|
-
module Wiring
|
|
5
|
-
module DataStore
|
|
6
|
-
class Redis < Base
|
|
7
|
-
# @!attribute redis
|
|
8
|
-
# @return [::Redis, ConnectionPool<::Redis>]
|
|
9
|
-
attr_reader :redis
|
|
10
|
-
|
|
11
|
-
# @!attribute warn_on_clock_skew
|
|
12
|
-
# @return [Boolean]
|
|
13
|
-
attr_reader :warn_on_clock_skew
|
|
14
|
-
|
|
15
|
-
# @param redis [::Redis, ConnectionPool<::Redis>]
|
|
16
|
-
# @param warn_on_clock_skew [Boolean] (true) Whether to warn about clock skew between Redis and
|
|
17
|
-
# the application server
|
|
18
|
-
def initialize(redis, warn_on_clock_skew: true)
|
|
19
|
-
@warn_on_clock_skew = warn_on_clock_skew
|
|
20
|
-
@redis = redis
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Stoplight
|
|
4
|
-
module Wiring
|
|
5
|
-
# Builds the default LightFactory from user-provided configuration which is
|
|
6
|
-
# used as the basis for all circuit breakers.
|
|
7
|
-
#
|
|
8
|
-
class DefaultFactoryBuilder
|
|
9
|
-
# @!attribute [r] configuration
|
|
10
|
-
# @return [Stoplight::Wiring::DefaultConfiguration]
|
|
11
|
-
#
|
|
12
|
-
attr_reader :configuration
|
|
13
|
-
|
|
14
|
-
def initialize
|
|
15
|
-
@configuration = DefaultConfiguration.new
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# @return [Stoplight::Wiring::LightFactory]
|
|
19
|
-
# @api private the method is used internally by Stoplight
|
|
20
|
-
def build
|
|
21
|
-
LightFactory.new(configuration.to_h)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Stoplight
|
|
4
|
-
module Wiring
|
|
5
|
-
module Light
|
|
6
|
-
# Provides default settings for the Stoplight library.
|
|
7
|
-
# @api private
|
|
8
|
-
DefaultConfig = Domain::Config.empty.with(
|
|
9
|
-
cool_off_time: Default::COOL_OFF_TIME,
|
|
10
|
-
threshold: Default::THRESHOLD,
|
|
11
|
-
recovery_threshold: Default::RECOVERY_THRESHOLD,
|
|
12
|
-
window_size: Default::WINDOW_SIZE,
|
|
13
|
-
tracked_errors: Default::TRACKED_ERRORS,
|
|
14
|
-
skipped_errors: Default::SKIPPED_ERRORS
|
|
15
|
-
)
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Stoplight
|
|
4
|
-
module Wiring
|
|
5
|
-
class LightFactory
|
|
6
|
-
# Validates that traffic control and recovery strategies are
|
|
7
|
-
# compatible with the provided configuration.
|
|
8
|
-
#
|
|
9
|
-
# Different strategies have different configuration requirements:
|
|
10
|
-
# - ErrorRate requires window_size and threshold ∈ [0,1]
|
|
11
|
-
# - ConsecutiveErrors requires threshold > 0
|
|
12
|
-
# - ConsecutiveSuccesses requires recovery_threshold > 0
|
|
13
|
-
#
|
|
14
|
-
# @raise [Stoplight::Error::ConfigurationError] if incompatible
|
|
15
|
-
class CompatibilityValidator
|
|
16
|
-
private attr_reader :dependencies
|
|
17
|
-
private attr_reader :config
|
|
18
|
-
|
|
19
|
-
class << self
|
|
20
|
-
def call(config, dependencies) = new(config, dependencies).call
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def initialize(config, dependencies)
|
|
24
|
-
@config = config
|
|
25
|
-
@dependencies = dependencies
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def call
|
|
29
|
-
validate_traffic_control!
|
|
30
|
-
validate_traffic_recovery!
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
private def validate_traffic_control!
|
|
34
|
-
traffic_control = dependencies.fetch(:traffic_control)
|
|
35
|
-
traffic_control.check_compatibility(config).then do |compatibility_result|
|
|
36
|
-
if compatibility_result.incompatible?
|
|
37
|
-
raise Domain::Error::ConfigurationError,
|
|
38
|
-
"#{traffic_control.class.name} incompatible with config: #{compatibility_result.error_messages}"
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def validate_traffic_recovery!
|
|
44
|
-
traffic_recovery = dependencies.fetch(:traffic_recovery)
|
|
45
|
-
traffic_recovery.check_compatibility(config).then do |compatibility_result|
|
|
46
|
-
if compatibility_result.incompatible?
|
|
47
|
-
raise Domain::Error::ConfigurationError,
|
|
48
|
-
"#{traffic_recovery.class.name} incompatible with config: #{compatibility_result.error_messages}"
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|