stoplight 5.3.8 → 5.5.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 +16 -1
- data/lib/generators/stoplight/install/templates/stoplight.rb.erb +2 -0
- data/lib/stoplight/admin/views/layout.erb +3 -3
- data/lib/stoplight/admin.rb +4 -4
- data/lib/stoplight/domain/color.rb +11 -0
- data/lib/stoplight/{config → domain}/compatibility_result.rb +1 -1
- data/lib/stoplight/domain/config.rb +55 -0
- data/lib/stoplight/{data_store/base.rb → domain/data_store.rb} +17 -15
- data/lib/stoplight/domain/error.rb +42 -0
- data/lib/stoplight/domain/failure.rb +42 -0
- data/lib/stoplight/domain/light/configuration_builder_interface.rb +130 -0
- data/lib/stoplight/domain/light.rb +198 -0
- data/lib/stoplight/domain/light_factory.rb +75 -0
- data/lib/stoplight/domain/metadata.rb +65 -0
- data/lib/stoplight/domain/state.rb +11 -0
- data/lib/stoplight/{notifier/base.rb → domain/state_transition_notifier.rb} +5 -4
- data/lib/stoplight/domain/strategies/green_run_strategy.rb +69 -0
- data/lib/stoplight/domain/strategies/red_run_strategy.rb +41 -0
- data/lib/stoplight/domain/strategies/run_strategy.rb +27 -0
- data/lib/stoplight/domain/strategies/yellow_run_strategy.rb +98 -0
- data/lib/stoplight/domain/tracker/base.rb +41 -0
- data/lib/stoplight/domain/tracker/recovery_probe.rb +72 -0
- data/lib/stoplight/domain/tracker/request.rb +67 -0
- data/lib/stoplight/domain/traffic_control/base.rb +74 -0
- data/lib/stoplight/domain/traffic_control/consecutive_errors.rb +57 -0
- data/lib/stoplight/domain/traffic_control/error_rate.rb +51 -0
- data/lib/stoplight/domain/traffic_recovery/base.rb +79 -0
- data/lib/stoplight/domain/traffic_recovery/consecutive_successes.rb +70 -0
- data/lib/stoplight/domain/traffic_recovery.rb +13 -0
- data/lib/stoplight/infrastructure/data_store/memory/sliding_window.rb +79 -0
- data/lib/stoplight/infrastructure/data_store/memory.rb +307 -0
- data/lib/stoplight/infrastructure/data_store/redis/lua.rb +25 -0
- data/lib/stoplight/infrastructure/data_store/redis.rb +478 -0
- data/lib/stoplight/infrastructure/dependency_injection/container.rb +249 -0
- data/lib/stoplight/infrastructure/dependency_injection/unresolved_dependency_error.rb +13 -0
- data/lib/stoplight/infrastructure/notifier/generic.rb +90 -0
- data/lib/stoplight/infrastructure/notifier/io.rb +23 -0
- data/lib/stoplight/infrastructure/notifier/logger.rb +21 -0
- data/lib/stoplight/rspec/generic_notifier.rb +1 -1
- data/lib/stoplight/version.rb +1 -1
- data/lib/stoplight/wiring/container.rb +80 -0
- data/lib/stoplight/wiring/default.rb +28 -0
- data/lib/stoplight/{config/user_default_config.rb → wiring/default_configuration.rb} +24 -31
- data/lib/stoplight/wiring/default_factory_builder.rb +25 -0
- data/lib/stoplight/wiring/fail_safe_data_store.rb +123 -0
- data/lib/stoplight/{notifier/fail_safe.rb → wiring/fail_safe_notifier.rb} +22 -13
- data/lib/stoplight/wiring/light/default_config.rb +18 -0
- data/lib/stoplight/wiring/light/system_config.rb +11 -0
- data/lib/stoplight/wiring/light_factory.rb +188 -0
- data/lib/stoplight/wiring/public_api.rb +28 -0
- data/lib/stoplight/wiring/system_container.rb +9 -0
- data/lib/stoplight/wiring/system_light_factory.rb +17 -0
- data/lib/stoplight.rb +38 -28
- metadata +53 -42
- data/lib/stoplight/color.rb +0 -9
- data/lib/stoplight/config/dsl.rb +0 -97
- data/lib/stoplight/config/library_default_config.rb +0 -21
- data/lib/stoplight/config/system_config.rb +0 -7
- data/lib/stoplight/data_store/fail_safe.rb +0 -113
- data/lib/stoplight/data_store/memory.rb +0 -311
- data/lib/stoplight/data_store/redis/lua.rb +0 -23
- data/lib/stoplight/data_store/redis.rb +0 -449
- data/lib/stoplight/data_store.rb +0 -6
- data/lib/stoplight/default.rb +0 -30
- data/lib/stoplight/error.rb +0 -10
- data/lib/stoplight/failure.rb +0 -71
- data/lib/stoplight/light/config.rb +0 -111
- data/lib/stoplight/light/configuration_builder_interface.rb +0 -128
- data/lib/stoplight/light/green_run_strategy.rb +0 -54
- data/lib/stoplight/light/red_run_strategy.rb +0 -27
- data/lib/stoplight/light/run_strategy.rb +0 -32
- data/lib/stoplight/light/yellow_run_strategy.rb +0 -94
- data/lib/stoplight/light.rb +0 -191
- data/lib/stoplight/metadata.rb +0 -99
- data/lib/stoplight/notifier/generic.rb +0 -79
- data/lib/stoplight/notifier/io.rb +0 -21
- data/lib/stoplight/notifier/logger.rb +0 -19
- data/lib/stoplight/state.rb +0 -9
- data/lib/stoplight/traffic_control/base.rb +0 -70
- data/lib/stoplight/traffic_control/consecutive_errors.rb +0 -55
- data/lib/stoplight/traffic_control/error_rate.rb +0 -49
- data/lib/stoplight/traffic_recovery/base.rb +0 -75
- data/lib/stoplight/traffic_recovery/consecutive_successes.rb +0 -68
- data/lib/stoplight/traffic_recovery.rb +0 -11
- /data/lib/stoplight/{data_store → infrastructure/data_store}/redis/get_metadata.lua +0 -0
- /data/lib/stoplight/{data_store → infrastructure/data_store}/redis/record_failure.lua +0 -0
- /data/lib/stoplight/{data_store → infrastructure/data_store}/redis/record_success.lua +0 -0
- /data/lib/stoplight/{data_store → infrastructure/data_store}/redis/transition_to_green.lua +0 -0
- /data/lib/stoplight/{data_store → infrastructure/data_store}/redis/transition_to_red.lua +0 -0
- /data/lib/stoplight/{data_store → infrastructure/data_store}/redis/transition_to_yellow.lua +0 -0
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.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Cameron Desautels
|
|
@@ -57,50 +57,61 @@ files:
|
|
|
57
57
|
- lib/stoplight/admin/views/_card.erb
|
|
58
58
|
- lib/stoplight/admin/views/index.erb
|
|
59
59
|
- lib/stoplight/admin/views/layout.erb
|
|
60
|
-
- lib/stoplight/color.rb
|
|
61
|
-
- lib/stoplight/
|
|
62
|
-
- lib/stoplight/config
|
|
63
|
-
- lib/stoplight/
|
|
64
|
-
- lib/stoplight/
|
|
65
|
-
- lib/stoplight/
|
|
66
|
-
- lib/stoplight/
|
|
67
|
-
- lib/stoplight/
|
|
68
|
-
- lib/stoplight/
|
|
69
|
-
- lib/stoplight/
|
|
70
|
-
- lib/stoplight/
|
|
71
|
-
- lib/stoplight/
|
|
72
|
-
- lib/stoplight/
|
|
73
|
-
- lib/stoplight/
|
|
74
|
-
- lib/stoplight/
|
|
75
|
-
- lib/stoplight/
|
|
76
|
-
- lib/stoplight/
|
|
77
|
-
- lib/stoplight/
|
|
78
|
-
- lib/stoplight/
|
|
79
|
-
- lib/stoplight/
|
|
80
|
-
- lib/stoplight/
|
|
81
|
-
- lib/stoplight/
|
|
82
|
-
- lib/stoplight/
|
|
83
|
-
- lib/stoplight/
|
|
84
|
-
- lib/stoplight/
|
|
85
|
-
- lib/stoplight/
|
|
86
|
-
- lib/stoplight/
|
|
87
|
-
- lib/stoplight/
|
|
88
|
-
- lib/stoplight/
|
|
89
|
-
- lib/stoplight/
|
|
90
|
-
- lib/stoplight/
|
|
91
|
-
- lib/stoplight/
|
|
92
|
-
- lib/stoplight/
|
|
93
|
-
- lib/stoplight/
|
|
60
|
+
- lib/stoplight/domain/color.rb
|
|
61
|
+
- lib/stoplight/domain/compatibility_result.rb
|
|
62
|
+
- lib/stoplight/domain/config.rb
|
|
63
|
+
- lib/stoplight/domain/data_store.rb
|
|
64
|
+
- lib/stoplight/domain/error.rb
|
|
65
|
+
- lib/stoplight/domain/failure.rb
|
|
66
|
+
- lib/stoplight/domain/light.rb
|
|
67
|
+
- lib/stoplight/domain/light/configuration_builder_interface.rb
|
|
68
|
+
- lib/stoplight/domain/light_factory.rb
|
|
69
|
+
- lib/stoplight/domain/metadata.rb
|
|
70
|
+
- lib/stoplight/domain/state.rb
|
|
71
|
+
- lib/stoplight/domain/state_transition_notifier.rb
|
|
72
|
+
- lib/stoplight/domain/strategies/green_run_strategy.rb
|
|
73
|
+
- lib/stoplight/domain/strategies/red_run_strategy.rb
|
|
74
|
+
- lib/stoplight/domain/strategies/run_strategy.rb
|
|
75
|
+
- lib/stoplight/domain/strategies/yellow_run_strategy.rb
|
|
76
|
+
- lib/stoplight/domain/tracker/base.rb
|
|
77
|
+
- lib/stoplight/domain/tracker/recovery_probe.rb
|
|
78
|
+
- lib/stoplight/domain/tracker/request.rb
|
|
79
|
+
- lib/stoplight/domain/traffic_control/base.rb
|
|
80
|
+
- lib/stoplight/domain/traffic_control/consecutive_errors.rb
|
|
81
|
+
- lib/stoplight/domain/traffic_control/error_rate.rb
|
|
82
|
+
- lib/stoplight/domain/traffic_recovery.rb
|
|
83
|
+
- lib/stoplight/domain/traffic_recovery/base.rb
|
|
84
|
+
- lib/stoplight/domain/traffic_recovery/consecutive_successes.rb
|
|
85
|
+
- lib/stoplight/infrastructure/data_store/memory.rb
|
|
86
|
+
- lib/stoplight/infrastructure/data_store/memory/sliding_window.rb
|
|
87
|
+
- lib/stoplight/infrastructure/data_store/redis.rb
|
|
88
|
+
- lib/stoplight/infrastructure/data_store/redis/get_metadata.lua
|
|
89
|
+
- lib/stoplight/infrastructure/data_store/redis/lua.rb
|
|
90
|
+
- lib/stoplight/infrastructure/data_store/redis/record_failure.lua
|
|
91
|
+
- lib/stoplight/infrastructure/data_store/redis/record_success.lua
|
|
92
|
+
- lib/stoplight/infrastructure/data_store/redis/transition_to_green.lua
|
|
93
|
+
- lib/stoplight/infrastructure/data_store/redis/transition_to_red.lua
|
|
94
|
+
- lib/stoplight/infrastructure/data_store/redis/transition_to_yellow.lua
|
|
95
|
+
- lib/stoplight/infrastructure/dependency_injection/container.rb
|
|
96
|
+
- lib/stoplight/infrastructure/dependency_injection/unresolved_dependency_error.rb
|
|
97
|
+
- lib/stoplight/infrastructure/notifier/generic.rb
|
|
98
|
+
- lib/stoplight/infrastructure/notifier/io.rb
|
|
99
|
+
- lib/stoplight/infrastructure/notifier/logger.rb
|
|
94
100
|
- lib/stoplight/rspec.rb
|
|
95
101
|
- lib/stoplight/rspec/generic_notifier.rb
|
|
96
|
-
- lib/stoplight/state.rb
|
|
97
|
-
- lib/stoplight/traffic_control/base.rb
|
|
98
|
-
- lib/stoplight/traffic_control/consecutive_errors.rb
|
|
99
|
-
- lib/stoplight/traffic_control/error_rate.rb
|
|
100
|
-
- lib/stoplight/traffic_recovery.rb
|
|
101
|
-
- lib/stoplight/traffic_recovery/base.rb
|
|
102
|
-
- lib/stoplight/traffic_recovery/consecutive_successes.rb
|
|
103
102
|
- lib/stoplight/version.rb
|
|
103
|
+
- lib/stoplight/wiring/container.rb
|
|
104
|
+
- lib/stoplight/wiring/default.rb
|
|
105
|
+
- lib/stoplight/wiring/default_configuration.rb
|
|
106
|
+
- 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
|
+
- lib/stoplight/wiring/light/default_config.rb
|
|
110
|
+
- lib/stoplight/wiring/light/system_config.rb
|
|
111
|
+
- lib/stoplight/wiring/light_factory.rb
|
|
112
|
+
- lib/stoplight/wiring/public_api.rb
|
|
113
|
+
- lib/stoplight/wiring/system_container.rb
|
|
114
|
+
- lib/stoplight/wiring/system_light_factory.rb
|
|
104
115
|
homepage: https://github.com/bolshakov/stoplight
|
|
105
116
|
licenses:
|
|
106
117
|
- MIT
|
data/lib/stoplight/color.rb
DELETED
data/lib/stoplight/config/dsl.rb
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Stoplight
|
|
4
|
-
module Config
|
|
5
|
-
# This is a DSL for configuring Stoplight settings. It is responsible for
|
|
6
|
-
# transforming the provided settings into a format that can be used by Stoplight.
|
|
7
|
-
#
|
|
8
|
-
# @api private
|
|
9
|
-
class DSL
|
|
10
|
-
def transform(settings)
|
|
11
|
-
if settings.has_key?(:data_store)
|
|
12
|
-
settings[:data_store] = build_data_store(settings[:data_store])
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
if settings.has_key?(:notifiers)
|
|
16
|
-
settings[:notifiers] = build_notifiers(settings[:notifiers])
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
if settings.has_key?(:tracked_errors)
|
|
20
|
-
settings[:tracked_errors] = build_tracked_errors(settings[:tracked_errors])
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
if settings.has_key?(:skipped_errors)
|
|
24
|
-
settings[:skipped_errors] = build_skipped_errors(settings[:skipped_errors])
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
if settings.has_key?(:cool_off_time)
|
|
28
|
-
settings[:cool_off_time] = build_cool_off_time(settings[:cool_off_time])
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
if settings.has_key?(:traffic_control)
|
|
32
|
-
settings[:traffic_control] = build_traffic_control(settings[:traffic_control])
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
if settings.has_key?(:traffic_recovery)
|
|
36
|
-
settings[:traffic_recovery] = build_traffic_recovery(settings[:traffic_recovery])
|
|
37
|
-
end
|
|
38
|
-
settings
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
private
|
|
42
|
-
|
|
43
|
-
def build_data_store(data_store)
|
|
44
|
-
DataStore::FailSafe.wrap(data_store)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def build_notifiers(notifiers)
|
|
48
|
-
notifiers.map { |notifier| Notifier::FailSafe.wrap(notifier) }
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def build_tracked_errors(tracked_error)
|
|
52
|
-
Array(tracked_error)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def build_skipped_errors(skipped_errors)
|
|
56
|
-
Array(skipped_errors)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def build_cool_off_time(cool_off_time)
|
|
60
|
-
cool_off_time.to_i
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def build_traffic_control(traffic_control)
|
|
64
|
-
case traffic_control
|
|
65
|
-
in Stoplight::TrafficControl::Base
|
|
66
|
-
traffic_control
|
|
67
|
-
in :consecutive_errors
|
|
68
|
-
Stoplight::TrafficControl::ConsecutiveErrors.new
|
|
69
|
-
in :error_rate
|
|
70
|
-
Stoplight::TrafficControl::ErrorRate.new
|
|
71
|
-
in {error_rate: error_rate_settings}
|
|
72
|
-
Stoplight::TrafficControl::ErrorRate.new(**error_rate_settings)
|
|
73
|
-
else
|
|
74
|
-
raise Error::ConfigurationError, <<~ERROR
|
|
75
|
-
unsupported traffic_control strategy provided (`#{traffic_control}`). Supported options:
|
|
76
|
-
* Stoplight::TrafficControl::ConsecutiveErrors
|
|
77
|
-
* Stoplight::TrafficControl::ErrorRate
|
|
78
|
-
ERROR
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def build_traffic_recovery(traffic_recovery)
|
|
83
|
-
case traffic_recovery
|
|
84
|
-
in Stoplight::TrafficRecovery::Base
|
|
85
|
-
traffic_recovery
|
|
86
|
-
in :consecutive_successes
|
|
87
|
-
Stoplight::TrafficRecovery::ConsecutiveSuccesses.new
|
|
88
|
-
else
|
|
89
|
-
raise Error::ConfigurationError, <<~ERROR
|
|
90
|
-
unsupported traffic_recovery strategy provided (`#{traffic_recovery}`). Supported options:
|
|
91
|
-
* Stoplight::TrafficRecovery::ConsecutiveSuccesses
|
|
92
|
-
ERROR
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
end
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Stoplight
|
|
4
|
-
module Config
|
|
5
|
-
# Provides default settings for the Stoplight library.
|
|
6
|
-
# @api private
|
|
7
|
-
LibraryDefaultConfig = Light::Config.empty.with(
|
|
8
|
-
cool_off_time: Stoplight::Default::COOL_OFF_TIME,
|
|
9
|
-
data_store: Stoplight::Default::DATA_STORE,
|
|
10
|
-
error_notifier: Stoplight::Default::ERROR_NOTIFIER,
|
|
11
|
-
notifiers: Stoplight::Default::NOTIFIERS,
|
|
12
|
-
threshold: Stoplight::Default::THRESHOLD,
|
|
13
|
-
recovery_threshold: Stoplight::Default::RECOVERY_THRESHOLD,
|
|
14
|
-
window_size: Stoplight::Default::WINDOW_SIZE,
|
|
15
|
-
tracked_errors: Stoplight::Default::TRACKED_ERRORS,
|
|
16
|
-
skipped_errors: Stoplight::Default::SKIPPED_ERRORS,
|
|
17
|
-
traffic_control: Stoplight::Default::TRAFFIC_CONTROL,
|
|
18
|
-
traffic_recovery: Stoplight::Default::TRAFFIC_RECOVERY
|
|
19
|
-
)
|
|
20
|
-
end
|
|
21
|
-
end
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "securerandom"
|
|
4
|
-
|
|
5
|
-
module Stoplight
|
|
6
|
-
module DataStore
|
|
7
|
-
# A wrapper around a data store that provides fail-safe mechanisms using a
|
|
8
|
-
# circuit breaker. It ensures that operations on the data store can gracefully
|
|
9
|
-
# handle failures by falling back to default values when necessary.
|
|
10
|
-
#
|
|
11
|
-
# @api private
|
|
12
|
-
class FailSafe < Base
|
|
13
|
-
# @!attribute [r] data_store
|
|
14
|
-
# @return [Stoplight::DataStore::Base] The underlying data store being wrapped.
|
|
15
|
-
protected attr_reader :data_store
|
|
16
|
-
|
|
17
|
-
class << self
|
|
18
|
-
# Wraps a data store with fail-safe mechanisms.
|
|
19
|
-
#
|
|
20
|
-
# @param data_store [Stoplight::DataStore::Base] The data store to wrap.
|
|
21
|
-
# @return [Stoplight::DataStore::Base, FailSafe] The original data store if it is already
|
|
22
|
-
# a +Memory+ or +FailSafe+ instance, otherwise a new +FailSafe+ instance.
|
|
23
|
-
def wrap(data_store)
|
|
24
|
-
case data_store
|
|
25
|
-
when Memory, FailSafe
|
|
26
|
-
data_store
|
|
27
|
-
else
|
|
28
|
-
new(data_store)
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# @param data_store [Stoplight::DataStore::Base]
|
|
34
|
-
def initialize(data_store)
|
|
35
|
-
@data_store = data_store
|
|
36
|
-
@circuit_breaker = Stoplight(
|
|
37
|
-
"stoplight:data_store:fail_safe:#{data_store.class.name}",
|
|
38
|
-
data_store: Default::DATA_STORE,
|
|
39
|
-
traffic_control: TrafficControl::ConsecutiveErrors.new,
|
|
40
|
-
threshold: Default::THRESHOLD
|
|
41
|
-
)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def names
|
|
45
|
-
with_fallback([]) do
|
|
46
|
-
data_store.names
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def get_metadata(config)
|
|
51
|
-
with_fallback(Metadata.new, config) do
|
|
52
|
-
data_store.get_metadata(config)
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def record_failure(config, failure)
|
|
57
|
-
with_fallback(Metadata.new, config) do
|
|
58
|
-
data_store.record_failure(config, failure)
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def record_success(config, **args)
|
|
63
|
-
with_fallback(nil, config) do
|
|
64
|
-
data_store.record_success(config, **args)
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def record_recovery_probe_success(config, **args)
|
|
69
|
-
with_fallback(Metadata.new, config) do
|
|
70
|
-
data_store.record_recovery_probe_success(config, **args)
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def record_recovery_probe_failure(config, failure)
|
|
75
|
-
with_fallback(Metadata.new, config) do
|
|
76
|
-
data_store.record_recovery_probe_failure(config, failure)
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def set_state(config, state)
|
|
81
|
-
with_fallback(State::UNLOCKED, config) do
|
|
82
|
-
data_store.set_state(config, state)
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def transition_to_color(config, color)
|
|
87
|
-
with_fallback(false, config) do
|
|
88
|
-
data_store.transition_to_color(config, color)
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def ==(other)
|
|
93
|
-
other.is_a?(self.class) && other.data_store == data_store
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
# @param default [Object, nil]
|
|
97
|
-
# @param config [Stoplight::Light::Config]
|
|
98
|
-
private def with_fallback(default = nil, config = nil, &code)
|
|
99
|
-
fallback = proc do |error|
|
|
100
|
-
config.error_notifier.call(error) if config && error
|
|
101
|
-
default
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
circuit_breaker.run(fallback, &code)
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
# @return [Stoplight::Light] The circuit breaker used to handle failures.
|
|
108
|
-
private def circuit_breaker
|
|
109
|
-
@circuit_breaker ||= Stoplight.system_light("stoplight:data_store:fail_safe:#{data_store.class.name}")
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
end
|
|
@@ -1,311 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "monitor"
|
|
4
|
-
|
|
5
|
-
module Stoplight
|
|
6
|
-
module DataStore
|
|
7
|
-
# @see Base
|
|
8
|
-
class Memory < Base
|
|
9
|
-
include MonitorMixin
|
|
10
|
-
|
|
11
|
-
KEY_SEPARATOR = ":"
|
|
12
|
-
|
|
13
|
-
def initialize
|
|
14
|
-
@errors = Hash.new { |h, k| h[k] = [] }
|
|
15
|
-
@successes = Hash.new { |h, k| h[k] = [] }
|
|
16
|
-
|
|
17
|
-
@recovery_probe_errors = Hash.new { |h, k| h[k] = [] }
|
|
18
|
-
@recovery_probe_successes = Hash.new { |h, k| h[k] = [] }
|
|
19
|
-
|
|
20
|
-
@metadata = Hash.new { |h, k| h[k] = Metadata.new }
|
|
21
|
-
super # MonitorMixin
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# @return [Array<String>]
|
|
25
|
-
def names
|
|
26
|
-
synchronize { @metadata.keys }
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# @param config [Stoplight::Light::Config]
|
|
30
|
-
# @return [Stoplight::Metadata]
|
|
31
|
-
def get_metadata(config)
|
|
32
|
-
light_name = config.name
|
|
33
|
-
|
|
34
|
-
synchronize do
|
|
35
|
-
current_time = Time.now
|
|
36
|
-
recovery_window = (current_time - config.cool_off_time)..current_time
|
|
37
|
-
recovered_at = @metadata[light_name].recovered_at
|
|
38
|
-
window = if config.window_size
|
|
39
|
-
window_start = [recovered_at, (current_time - config.window_size)].compact.max
|
|
40
|
-
(window_start..current_time)
|
|
41
|
-
else
|
|
42
|
-
(..current_time)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
errors = @errors[config.name].count do |request_time|
|
|
46
|
-
window.cover?(request_time)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
successes = @successes[config.name].count do |request_time|
|
|
50
|
-
window.cover?(request_time)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
recovery_probe_errors = @recovery_probe_errors[config.name].count do |request_time|
|
|
54
|
-
recovery_window.cover?(request_time)
|
|
55
|
-
end
|
|
56
|
-
recovery_probe_successes = @recovery_probe_successes[config.name].count do |request_time|
|
|
57
|
-
recovery_window.cover?(request_time)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
@metadata[light_name].with(
|
|
61
|
-
current_time:,
|
|
62
|
-
errors:,
|
|
63
|
-
successes:,
|
|
64
|
-
recovery_probe_errors:,
|
|
65
|
-
recovery_probe_successes:
|
|
66
|
-
)
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
# @param metrics [<Time>]
|
|
71
|
-
# @param window_size [Numeric, nil]
|
|
72
|
-
# @return [void]
|
|
73
|
-
def cleanup(metrics, window_size:)
|
|
74
|
-
min_age = Time.now - [window_size&.*(3), METRICS_RETENTION_TIME].compact.min
|
|
75
|
-
|
|
76
|
-
metrics.reject! { _1 < min_age }
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
# @param config [Stoplight::Light::Config]
|
|
80
|
-
# @param failure [Stoplight::Failure]
|
|
81
|
-
# @return [Stoplight::Metadata]
|
|
82
|
-
def record_failure(config, failure)
|
|
83
|
-
light_name = config.name
|
|
84
|
-
|
|
85
|
-
synchronize do
|
|
86
|
-
@errors[light_name].unshift(failure.time) if config.window_size
|
|
87
|
-
|
|
88
|
-
cleanup(@errors[light_name], window_size: config.window_size)
|
|
89
|
-
|
|
90
|
-
metadata = @metadata[light_name]
|
|
91
|
-
@metadata[light_name] = if metadata.last_error_at.nil? || failure.time > metadata.last_error_at
|
|
92
|
-
metadata.with(
|
|
93
|
-
last_error_at: failure.time,
|
|
94
|
-
last_error: failure,
|
|
95
|
-
consecutive_errors: metadata.consecutive_errors.succ,
|
|
96
|
-
consecutive_successes: 0
|
|
97
|
-
)
|
|
98
|
-
else
|
|
99
|
-
metadata.with(
|
|
100
|
-
consecutive_errors: metadata.consecutive_errors.succ,
|
|
101
|
-
consecutive_successes: 0
|
|
102
|
-
)
|
|
103
|
-
end
|
|
104
|
-
get_metadata(config)
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
# @param config [Stoplight::Light::Config]
|
|
109
|
-
# @param request_id [String]
|
|
110
|
-
# @param request_time [Time]
|
|
111
|
-
# @return [void]
|
|
112
|
-
def record_success(config, request_time: Time.now, request_id: SecureRandom.hex(12))
|
|
113
|
-
light_name = config.name
|
|
114
|
-
|
|
115
|
-
synchronize do
|
|
116
|
-
@successes[light_name].unshift(request_time) if config.window_size
|
|
117
|
-
cleanup(@successes[light_name], window_size: config.window_size)
|
|
118
|
-
|
|
119
|
-
metadata = @metadata[light_name]
|
|
120
|
-
@metadata[light_name] = if metadata.last_success_at.nil? || request_time > metadata.last_success_at
|
|
121
|
-
metadata.with(
|
|
122
|
-
last_success_at: request_time,
|
|
123
|
-
consecutive_errors: 0,
|
|
124
|
-
consecutive_successes: metadata.consecutive_successes.succ
|
|
125
|
-
)
|
|
126
|
-
else
|
|
127
|
-
metadata.with(
|
|
128
|
-
consecutive_errors: 0,
|
|
129
|
-
consecutive_successes: metadata.consecutive_successes.succ
|
|
130
|
-
)
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
# @param config [Stoplight::Light::Config]
|
|
136
|
-
# @param failure [Stoplight::Failure]
|
|
137
|
-
# @return [Stoplight::Metadata]
|
|
138
|
-
def record_recovery_probe_failure(config, failure)
|
|
139
|
-
light_name = config.name
|
|
140
|
-
|
|
141
|
-
synchronize do
|
|
142
|
-
@recovery_probe_errors[light_name].unshift(failure.time)
|
|
143
|
-
cleanup(@recovery_probe_errors[light_name], window_size: config.cool_off_time)
|
|
144
|
-
|
|
145
|
-
metadata = @metadata[light_name]
|
|
146
|
-
@metadata[light_name] = if metadata.last_error_at.nil? || failure.time > metadata.last_error_at
|
|
147
|
-
metadata.with(
|
|
148
|
-
last_error_at: failure.time,
|
|
149
|
-
last_error: failure,
|
|
150
|
-
consecutive_errors: metadata.consecutive_errors.succ,
|
|
151
|
-
consecutive_successes: 0
|
|
152
|
-
)
|
|
153
|
-
else
|
|
154
|
-
metadata.with(
|
|
155
|
-
consecutive_errors: metadata.consecutive_errors.succ,
|
|
156
|
-
consecutive_successes: 0
|
|
157
|
-
)
|
|
158
|
-
end
|
|
159
|
-
get_metadata(config)
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
# @param config [Stoplight::Light::Config]
|
|
164
|
-
# @param request_id [String]
|
|
165
|
-
# @param request_time [Time]
|
|
166
|
-
# @return [Stoplight::Metadata]
|
|
167
|
-
def record_recovery_probe_success(config, request_time: Time.now, request_id: SecureRandom.hex(12))
|
|
168
|
-
light_name = config.name
|
|
169
|
-
|
|
170
|
-
synchronize do
|
|
171
|
-
@recovery_probe_successes[light_name].unshift(request_time)
|
|
172
|
-
cleanup(@recovery_probe_successes[light_name], window_size: config.cool_off_time)
|
|
173
|
-
|
|
174
|
-
metadata = @metadata[light_name]
|
|
175
|
-
@metadata[light_name] = if metadata.last_success_at.nil? || request_time > metadata.last_success_at
|
|
176
|
-
metadata.with(
|
|
177
|
-
last_success_at: request_time,
|
|
178
|
-
consecutive_errors: 0,
|
|
179
|
-
consecutive_successes: metadata.consecutive_successes.succ
|
|
180
|
-
)
|
|
181
|
-
else
|
|
182
|
-
metadata.with(
|
|
183
|
-
consecutive_errors: 0,
|
|
184
|
-
consecutive_successes: metadata.consecutive_successes.succ
|
|
185
|
-
)
|
|
186
|
-
end
|
|
187
|
-
get_metadata(config)
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
# @param config [Stoplight::Light::Config]
|
|
192
|
-
# @param state [String]
|
|
193
|
-
# @return [String]
|
|
194
|
-
def set_state(config, state)
|
|
195
|
-
light_name = config.name
|
|
196
|
-
|
|
197
|
-
synchronize do
|
|
198
|
-
metadata = @metadata[light_name]
|
|
199
|
-
@metadata[light_name] = metadata.with(locked_state: state)
|
|
200
|
-
end
|
|
201
|
-
state
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
# @return [String]
|
|
205
|
-
def inspect
|
|
206
|
-
"#<#{self.class.name}>"
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
# Combined method that performs the state transition based on color
|
|
210
|
-
#
|
|
211
|
-
# @param config [Stoplight::Light::Config] The light configuration
|
|
212
|
-
# @param color [String] The color to transition to ("GREEN", "YELLOW", or "RED")
|
|
213
|
-
# @param current_time [Time]
|
|
214
|
-
# @return [Boolean] true if this is the first instance to detect this transition
|
|
215
|
-
def transition_to_color(config, color, current_time: Time.now)
|
|
216
|
-
case color
|
|
217
|
-
when Color::GREEN
|
|
218
|
-
transition_to_green(config)
|
|
219
|
-
when Color::YELLOW
|
|
220
|
-
transition_to_yellow(config, current_time:)
|
|
221
|
-
when Color::RED
|
|
222
|
-
transition_to_red(config, current_time:)
|
|
223
|
-
else
|
|
224
|
-
raise ArgumentError, "Invalid color: #{color}"
|
|
225
|
-
end
|
|
226
|
-
end
|
|
227
|
-
|
|
228
|
-
# Transitions to GREEN state and ensures only one notification
|
|
229
|
-
#
|
|
230
|
-
# @param config [Stoplight::Light::Config] The light configuration
|
|
231
|
-
# @return [Boolean] true if this is the first instance to detect this transition
|
|
232
|
-
private def transition_to_green(config, current_time: Time.now)
|
|
233
|
-
light_name = config.name
|
|
234
|
-
|
|
235
|
-
synchronize do
|
|
236
|
-
metadata = @metadata[light_name]
|
|
237
|
-
if metadata.recovered_at
|
|
238
|
-
false
|
|
239
|
-
else
|
|
240
|
-
@metadata[light_name] = metadata.with(
|
|
241
|
-
recovered_at: current_time,
|
|
242
|
-
recovery_started_at: nil,
|
|
243
|
-
breached_at: nil,
|
|
244
|
-
recovery_scheduled_after: nil
|
|
245
|
-
)
|
|
246
|
-
true
|
|
247
|
-
end
|
|
248
|
-
end
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
# Transitions to YELLOW (recovery) state and ensures only one notification
|
|
252
|
-
#
|
|
253
|
-
# @param config [Stoplight::Light::Config] The light configuration
|
|
254
|
-
# @param current_time [Time]
|
|
255
|
-
# @return [Boolean] true if this is the first instance to detect this transition
|
|
256
|
-
private def transition_to_yellow(config, current_time: Time.now)
|
|
257
|
-
light_name = config.name
|
|
258
|
-
|
|
259
|
-
synchronize do
|
|
260
|
-
metadata = @metadata[light_name]
|
|
261
|
-
if metadata.recovery_started_at.nil?
|
|
262
|
-
@metadata[light_name] = metadata.with(
|
|
263
|
-
recovery_started_at: current_time,
|
|
264
|
-
recovery_scheduled_after: nil,
|
|
265
|
-
recovered_at: nil,
|
|
266
|
-
breached_at: nil
|
|
267
|
-
)
|
|
268
|
-
true
|
|
269
|
-
else
|
|
270
|
-
@metadata[light_name] = metadata.with(
|
|
271
|
-
recovery_scheduled_after: nil,
|
|
272
|
-
recovered_at: nil,
|
|
273
|
-
breached_at: nil
|
|
274
|
-
)
|
|
275
|
-
false
|
|
276
|
-
end
|
|
277
|
-
end
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
# Transitions to RED state and ensures only one notification
|
|
281
|
-
#
|
|
282
|
-
# @param config [Stoplight::Light::Config] The light configuration
|
|
283
|
-
# @param current_time [Time]
|
|
284
|
-
# @return [Boolean] true if this is the first instance to detect this transition
|
|
285
|
-
private def transition_to_red(config, current_time: Time.now)
|
|
286
|
-
light_name = config.name
|
|
287
|
-
recovery_scheduled_after = current_time + config.cool_off_time
|
|
288
|
-
|
|
289
|
-
synchronize do
|
|
290
|
-
metadata = @metadata[light_name]
|
|
291
|
-
if metadata.breached_at
|
|
292
|
-
@metadata[light_name] = metadata.with(
|
|
293
|
-
recovery_scheduled_after: recovery_scheduled_after,
|
|
294
|
-
recovery_started_at: nil,
|
|
295
|
-
recovered_at: nil
|
|
296
|
-
)
|
|
297
|
-
false
|
|
298
|
-
else
|
|
299
|
-
@metadata[light_name] = metadata.with(
|
|
300
|
-
breached_at: current_time,
|
|
301
|
-
recovery_scheduled_after: recovery_scheduled_after,
|
|
302
|
-
recovery_started_at: nil,
|
|
303
|
-
recovered_at: nil
|
|
304
|
-
)
|
|
305
|
-
true
|
|
306
|
-
end
|
|
307
|
-
end
|
|
308
|
-
end
|
|
309
|
-
end
|
|
310
|
-
end
|
|
311
|
-
end
|