stoplight 5.7.0 → 5.8.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.
Files changed (235) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/UPGRADING.md +303 -0
  4. data/lib/generators/stoplight/install/install_generator.rb +6 -1
  5. data/lib/stoplight/admin/dependencies.rb +1 -1
  6. data/lib/stoplight/admin/helpers.rb +20 -4
  7. data/lib/stoplight/admin/lights_repository/light.rb +22 -6
  8. data/lib/stoplight/admin/lights_repository.rb +6 -5
  9. data/lib/stoplight/admin/views/_card.erb +8 -5
  10. data/lib/stoplight/color.rb +9 -0
  11. data/lib/stoplight/data_store.rb +28 -0
  12. data/lib/stoplight/domain/compatibility_result.rb +7 -7
  13. data/lib/stoplight/domain/config.rb +38 -39
  14. data/lib/stoplight/domain/error_tracking_policy.rb +27 -0
  15. data/lib/stoplight/domain/failure.rb +1 -1
  16. data/lib/stoplight/domain/light/configuration_builder_interface.rb +2 -0
  17. data/lib/stoplight/domain/light.rb +15 -46
  18. data/lib/stoplight/domain/light_info.rb +7 -0
  19. data/lib/stoplight/domain/metrics_snapshot.rb +58 -0
  20. data/lib/stoplight/domain/state_snapshot.rb +29 -23
  21. data/lib/stoplight/domain/storage/recovery_lock_token.rb +15 -0
  22. data/lib/stoplight/domain/strategies/green_run_strategy.rb +18 -26
  23. data/lib/stoplight/domain/strategies/red_run_strategy.rb +9 -12
  24. data/lib/stoplight/domain/strategies/yellow_run_strategy.rb +41 -51
  25. data/lib/stoplight/domain/tracker/recovery_probe.rb +16 -33
  26. data/lib/stoplight/domain/tracker/request.rb +12 -31
  27. data/lib/stoplight/domain/traffic_control/consecutive_errors.rb +8 -11
  28. data/lib/stoplight/domain/traffic_control/error_rate.rb +19 -15
  29. data/lib/stoplight/domain/traffic_recovery/consecutive_successes.rb +6 -10
  30. data/lib/stoplight/domain/traffic_recovery.rb +3 -4
  31. data/lib/stoplight/error.rb +46 -0
  32. data/lib/stoplight/infrastructure/{data_store/fail_safe.rb → fail_safe/data_store.rb} +39 -51
  33. data/lib/stoplight/infrastructure/fail_safe/storage/metrics.rb +65 -0
  34. data/lib/stoplight/infrastructure/fail_safe/storage/recovery_lock.rb +69 -0
  35. data/lib/stoplight/infrastructure/fail_safe/storage/recovery_lock_token.rb +19 -0
  36. data/lib/stoplight/infrastructure/fail_safe/storage/state.rb +62 -0
  37. data/lib/stoplight/infrastructure/{data_store/memory → memory/data_store}/metrics.rb +2 -2
  38. data/lib/stoplight/infrastructure/{data_store/memory → memory/data_store}/recovery_lock_store.rb +10 -12
  39. data/lib/stoplight/infrastructure/{data_store/memory → memory/data_store}/recovery_lock_token.rb +3 -6
  40. data/lib/stoplight/infrastructure/{data_store/memory → memory/data_store}/sliding_window.rb +21 -26
  41. data/lib/stoplight/infrastructure/{data_store/memory → memory/data_store}/state.rb +3 -3
  42. data/lib/stoplight/infrastructure/{data_store/memory.rb → memory/data_store.rb} +36 -32
  43. data/lib/stoplight/infrastructure/memory/storage/recovery_lock.rb +35 -0
  44. data/lib/stoplight/infrastructure/memory/storage/recovery_metrics.rb +16 -0
  45. data/lib/stoplight/infrastructure/memory/storage/state.rb +155 -0
  46. data/lib/stoplight/infrastructure/memory/storage/unbounded_metrics.rb +103 -0
  47. data/lib/stoplight/infrastructure/memory/storage/window_metrics.rb +101 -0
  48. data/lib/stoplight/infrastructure/notifier/fail_safe.rb +9 -21
  49. data/lib/stoplight/infrastructure/notifier/generic.rb +4 -14
  50. data/lib/stoplight/infrastructure/notifier/io.rb +1 -2
  51. data/lib/stoplight/infrastructure/notifier/logger.rb +1 -2
  52. data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/recovery_lock_store.rb +9 -22
  53. data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/recovery_lock_token.rb +7 -14
  54. data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/scripting.rb +22 -20
  55. data/lib/stoplight/infrastructure/{data_store/redis.rb → redis/data_store.rb} +48 -56
  56. data/lib/stoplight/infrastructure/redis/storage/key_space.rb +51 -0
  57. data/lib/stoplight/infrastructure/redis/storage/metrics.rb +40 -0
  58. data/lib/stoplight/infrastructure/redis/storage/recovery_lock/release_lock.lua +6 -0
  59. data/lib/stoplight/infrastructure/redis/storage/recovery_lock.rb +64 -0
  60. data/lib/stoplight/infrastructure/redis/storage/recovery_metrics.rb +20 -0
  61. data/lib/stoplight/infrastructure/redis/storage/scripting.rb +18 -0
  62. data/lib/stoplight/infrastructure/redis/storage/state/transition_to_green.lua +10 -0
  63. data/lib/stoplight/infrastructure/redis/storage/state/transition_to_red.lua +10 -0
  64. data/lib/stoplight/infrastructure/redis/storage/state/transition_to_yellow.lua +9 -0
  65. data/lib/stoplight/infrastructure/redis/storage/state.rb +141 -0
  66. data/lib/stoplight/infrastructure/redis/storage/unbounded_metrics/record_failure.lua +28 -0
  67. data/lib/stoplight/infrastructure/redis/storage/unbounded_metrics/record_success.lua +26 -0
  68. data/lib/stoplight/infrastructure/redis/storage/unbounded_metrics.rb +123 -0
  69. data/lib/stoplight/infrastructure/redis/storage/window_metrics/metrics_snapshot.lua +26 -0
  70. data/lib/stoplight/infrastructure/redis/storage/window_metrics/record_failure.lua +36 -0
  71. data/lib/stoplight/infrastructure/redis/storage/window_metrics/record_success.lua +35 -0
  72. data/lib/stoplight/infrastructure/redis/storage/window_metrics.rb +174 -0
  73. data/lib/stoplight/infrastructure/storage/compatibility_metrics.rb +3 -10
  74. data/lib/stoplight/infrastructure/storage/compatibility_recovery_lock.rb +8 -11
  75. data/lib/stoplight/infrastructure/storage/compatibility_recovery_metrics.rb +6 -14
  76. data/lib/stoplight/infrastructure/storage/compatibility_state.rb +6 -17
  77. data/lib/stoplight/infrastructure/system_clock.rb +16 -0
  78. data/lib/stoplight/notifier.rb +11 -0
  79. data/lib/stoplight/state.rb +9 -0
  80. data/lib/stoplight/types.rb +29 -0
  81. data/lib/stoplight/undefined.rb +16 -0
  82. data/lib/stoplight/version.rb +1 -1
  83. data/lib/stoplight/wiring/config_compatibility_validator.rb +54 -0
  84. data/lib/stoplight/wiring/configuration_dsl.rb +101 -0
  85. data/lib/stoplight/wiring/data_store_backend.rb +26 -0
  86. data/lib/stoplight/wiring/default.rb +1 -1
  87. data/lib/stoplight/wiring/default_config.rb +21 -0
  88. data/lib/stoplight/wiring/default_configuration.rb +70 -53
  89. data/lib/stoplight/wiring/light_builder.rb +76 -63
  90. data/lib/stoplight/wiring/light_factory/traffic_control_dsl.rb +3 -3
  91. data/lib/stoplight/wiring/light_factory/traffic_recovery_dsl.rb +4 -4
  92. data/lib/stoplight/wiring/light_factory.rb +78 -52
  93. data/lib/stoplight/wiring/memory/backend.rb +57 -0
  94. data/lib/stoplight/wiring/redis/backend.rb +116 -0
  95. data/lib/stoplight/wiring/storage_set.rb +12 -0
  96. data/lib/stoplight/wiring/storage_set_builder.rb +51 -0
  97. data/lib/stoplight/wiring/system/light_builder.rb +47 -0
  98. data/lib/stoplight/wiring/system/light_factory.rb +64 -0
  99. data/lib/stoplight/wiring/system.rb +129 -0
  100. data/lib/stoplight.rb +196 -25
  101. data/sig/_private/generators/stoplight/install/install_generator.rbs +22 -0
  102. data/sig/_private/stoplight/common/deprecations.rbs +9 -0
  103. data/sig/_private/stoplight/data_store.rbs +6 -0
  104. data/sig/_private/stoplight/domain/compatibility_result.rbs +18 -0
  105. data/sig/_private/stoplight/domain/config.rbs +65 -0
  106. data/sig/_private/stoplight/domain/error_tracking_policy.rbs +14 -0
  107. data/sig/_private/stoplight/domain/failure.rbs +16 -0
  108. data/sig/_private/stoplight/domain/light.rbs +25 -0
  109. data/sig/_private/stoplight/domain/light_info.rbs +19 -0
  110. data/sig/_private/stoplight/domain/metrics_snapshot.rbs +38 -0
  111. data/sig/_private/stoplight/domain/ports/clock.rbs +18 -0
  112. data/sig/_private/stoplight/domain/ports/data_store.rbs +76 -0
  113. data/{lib/stoplight/domain/light_factory.rb → sig/_private/stoplight/domain/ports/light_factory.rbs} +33 -28
  114. data/sig/_private/stoplight/domain/ports/metrics_store.rbs +29 -0
  115. data/sig/_private/stoplight/domain/ports/recovery_lock_store.rbs +52 -0
  116. data/sig/_private/stoplight/domain/ports/recovery_lock_token.rbs +6 -0
  117. data/sig/_private/stoplight/domain/ports/run_strategy.rbs +14 -0
  118. data/sig/_private/stoplight/domain/ports/state_store.rbs +79 -0
  119. data/sig/_private/stoplight/domain/ports/traffic_control.rbs +41 -0
  120. data/sig/_private/stoplight/domain/ports/traffic_recovery.rbs +47 -0
  121. data/sig/_private/stoplight/domain/state_snapshot.rbs +32 -0
  122. data/sig/_private/stoplight/domain/storage/recovery_lock_token.rbs +11 -0
  123. data/sig/_private/stoplight/domain/strategies/green_run_strategy.rbs +17 -0
  124. data/sig/_private/stoplight/domain/strategies/red_run_strategy.rbs +17 -0
  125. data/sig/_private/stoplight/domain/strategies/yellow_run_strategy.rbs +42 -0
  126. data/{lib/stoplight/domain/tracker/base.rb → sig/_private/stoplight/domain/tracker/base.rbs} +0 -4
  127. data/sig/_private/stoplight/domain/tracker/recovery_probe.rbs +25 -0
  128. data/sig/_private/stoplight/domain/tracker/request.rbs +26 -0
  129. data/sig/_private/stoplight/domain/traffic_control/consecutive_errors.rbs +9 -0
  130. data/sig/_private/stoplight/domain/traffic_control/error_rate.rbs +13 -0
  131. data/sig/_private/stoplight/domain/traffic_recovery/consecutive_successes.rbs +9 -0
  132. data/sig/_private/stoplight/domain/traffic_recovery.rbs +9 -0
  133. data/sig/_private/stoplight/infrastructure/fail_safe/data_store.rbs +26 -0
  134. data/sig/_private/stoplight/infrastructure/fail_safe/storage/metrics.rbs +25 -0
  135. data/sig/_private/stoplight/infrastructure/fail_safe/storage/recovery_lock.rbs +29 -0
  136. data/sig/_private/stoplight/infrastructure/fail_safe/storage/recovery_lock_token.rbs +19 -0
  137. data/sig/_private/stoplight/infrastructure/fail_safe/storage/state.rbs +25 -0
  138. data/sig/_private/stoplight/infrastructure/memory/data_store/metrics.rbs +25 -0
  139. data/sig/_private/stoplight/infrastructure/memory/data_store/recovery_lock_store.rbs +19 -0
  140. data/sig/_private/stoplight/infrastructure/memory/data_store/recovery_lock_token.rbs +17 -0
  141. data/sig/_private/stoplight/infrastructure/memory/data_store/sliding_window.rbs +27 -0
  142. data/sig/_private/stoplight/infrastructure/memory/data_store/state.rbs +17 -0
  143. data/sig/_private/stoplight/infrastructure/memory/data_store.rbs +30 -0
  144. data/sig/_private/stoplight/infrastructure/memory/storage/recovery_lock.rbs +15 -0
  145. data/sig/_private/stoplight/infrastructure/memory/storage/recovery_metrics.rbs +10 -0
  146. data/sig/_private/stoplight/infrastructure/memory/storage/state.rbs +28 -0
  147. data/sig/_private/stoplight/infrastructure/memory/storage/unbounded_metrics.rbs +25 -0
  148. data/sig/_private/stoplight/infrastructure/memory/storage/window_metrics.rbs +26 -0
  149. data/sig/_private/stoplight/infrastructure/notifier/fail_safe.rbs +17 -0
  150. data/sig/_private/stoplight/infrastructure/notifier/generic.rbs +18 -0
  151. data/sig/_private/stoplight/infrastructure/notifier/io.rbs +14 -0
  152. data/sig/_private/stoplight/infrastructure/notifier/logger.rbs +14 -0
  153. data/sig/_private/stoplight/infrastructure/redis/data_store/recovery_lock_store.rbs +24 -0
  154. data/sig/_private/stoplight/infrastructure/redis/data_store/recovery_lock_token.rbs +21 -0
  155. data/sig/_private/stoplight/infrastructure/redis/data_store/scripting.rbs +34 -0
  156. data/sig/_private/stoplight/infrastructure/redis/data_store.rbs +67 -0
  157. data/sig/_private/stoplight/infrastructure/redis/storage/key_space.rbs +19 -0
  158. data/sig/_private/stoplight/infrastructure/redis/storage/metrics.rbs +17 -0
  159. data/sig/_private/stoplight/infrastructure/redis/storage/recovery_lock.rbs +26 -0
  160. data/sig/_private/stoplight/infrastructure/redis/storage/recovery_metrics.rbs +10 -0
  161. data/sig/_private/stoplight/infrastructure/redis/storage/scripting.rbs +13 -0
  162. data/sig/_private/stoplight/infrastructure/redis/storage/state.rbs +32 -0
  163. data/sig/_private/stoplight/infrastructure/redis/storage/unbounded_metrics.rbs +21 -0
  164. data/sig/_private/stoplight/infrastructure/redis/storage/window_metrics.rbs +34 -0
  165. data/sig/_private/stoplight/infrastructure/storage/compatibility_metrics.rbs +17 -0
  166. data/sig/_private/stoplight/infrastructure/storage/compatibility_recovery_lock.rbs +13 -0
  167. data/sig/_private/stoplight/infrastructure/storage/compatibility_recovery_metrics.rbs +14 -0
  168. data/sig/_private/stoplight/infrastructure/storage/compatibility_state.rbs +14 -0
  169. data/sig/_private/stoplight/infrastructure/system_clock.rbs +7 -0
  170. data/sig/_private/stoplight/system/light_builder.rbs +23 -0
  171. data/sig/_private/stoplight/system/light_factory.rbs +17 -0
  172. data/sig/_private/stoplight/types.rbs +6 -0
  173. data/sig/_private/stoplight/wiring/config_compatibility_validator.rbs +19 -0
  174. data/sig/_private/stoplight/wiring/configuration_dsl.rbs +43 -0
  175. data/sig/_private/stoplight/wiring/data_store_backend.rbs +11 -0
  176. data/sig/_private/stoplight/wiring/default.rbs +26 -0
  177. data/{lib/stoplight/wiring/data_store/memory.rb → sig/_private/stoplight/wiring/default_config.rbs} +1 -4
  178. data/sig/_private/stoplight/wiring/default_configuration.rbs +29 -0
  179. data/sig/_private/stoplight/wiring/light_builder.rbs +48 -0
  180. data/sig/_private/stoplight/wiring/light_factory/traffic_control_dsl.rbs +7 -0
  181. data/sig/_private/stoplight/wiring/light_factory/traffic_recovery_dsl.rbs +7 -0
  182. data/sig/_private/stoplight/wiring/light_factory.rbs +16 -0
  183. data/sig/_private/stoplight/wiring/memory/backend.rbs +26 -0
  184. data/sig/_private/stoplight/wiring/notifier_factory.rbs +10 -0
  185. data/sig/_private/stoplight/wiring/redis/backend.rbs +38 -0
  186. data/sig/_private/stoplight/wiring/storage_set.rbs +38 -0
  187. data/sig/_private/stoplight/wiring/storage_set_builder.rbs +15 -0
  188. data/sig/_private/stoplight/wiring/system.rbs +15 -0
  189. data/sig/_private/stoplight.rbs +48 -0
  190. data/sig/stoplight/color.rbs +7 -0
  191. data/sig/stoplight/data_store.rbs +19 -0
  192. data/sig/stoplight/error.rbs +20 -0
  193. data/sig/stoplight/notifier.rbs +11 -0
  194. data/sig/stoplight/ports/configuration.rbs +19 -0
  195. data/sig/stoplight/ports/exception_matcher.rbs +8 -0
  196. data/sig/stoplight/ports/light.rbs +12 -0
  197. data/sig/stoplight/ports/light_info.rbs +5 -0
  198. data/sig/stoplight/ports/state_transition_notifier.rbs +15 -0
  199. data/sig/stoplight/ports/system.rbs +21 -0
  200. data/sig/stoplight/state.rbs +7 -0
  201. data/sig/stoplight/undefined.rbs +9 -0
  202. data/sig/stoplight/version.rbs +3 -0
  203. data/sig/stoplight.rbs +66 -0
  204. metadata +175 -47
  205. data/lib/stoplight/domain/color.rb +0 -11
  206. data/lib/stoplight/domain/data_store.rb +0 -146
  207. data/lib/stoplight/domain/error.rb +0 -42
  208. data/lib/stoplight/domain/metrics.rb +0 -64
  209. data/lib/stoplight/domain/recovery_lock_token.rb +0 -15
  210. data/lib/stoplight/domain/state.rb +0 -11
  211. data/lib/stoplight/domain/state_transition_notifier.rb +0 -25
  212. data/lib/stoplight/domain/storage/metrics.rb +0 -42
  213. data/lib/stoplight/domain/storage/recovery_lock.rb +0 -56
  214. data/lib/stoplight/domain/storage/state.rb +0 -87
  215. data/lib/stoplight/domain/strategies/run_strategy.rb +0 -22
  216. data/lib/stoplight/domain/traffic_control/base.rb +0 -74
  217. data/lib/stoplight/domain/traffic_recovery/base.rb +0 -79
  218. data/lib/stoplight/wiring/data_store/base.rb +0 -11
  219. data/lib/stoplight/wiring/data_store/redis.rb +0 -25
  220. data/lib/stoplight/wiring/default_factory_builder.rb +0 -25
  221. data/lib/stoplight/wiring/light/default_config.rb +0 -18
  222. data/lib/stoplight/wiring/light/system_config.rb +0 -11
  223. data/lib/stoplight/wiring/light_factory/compatibility_validator.rb +0 -55
  224. data/lib/stoplight/wiring/light_factory/config_normalizer.rb +0 -71
  225. data/lib/stoplight/wiring/light_factory/configuration_pipeline.rb +0 -72
  226. data/lib/stoplight/wiring/public_api.rb +0 -29
  227. /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/get_metrics.lua +0 -0
  228. /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/record_failure.lua +0 -0
  229. /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/record_recovery_probe_failure.lua +0 -0
  230. /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/record_recovery_probe_success.lua +0 -0
  231. /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/record_success.lua +0 -0
  232. /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/release_lock.lua +0 -0
  233. /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/transition_to_green.lua +0 -0
  234. /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/transition_to_red.lua +0 -0
  235. /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/transition_to_yellow.lua +0 -0
@@ -4,24 +4,6 @@ module Stoplight
4
4
  module Domain
5
5
  # A +Stoplight::Light+ configuration object.
6
6
  #
7
- # # @!attribute [r] name
8
- # @return [String]
9
- #
10
- # @!attribute [r] cool_off_time - cool-off time in seconds
11
- # @return [Numeric]
12
- #
13
- # @!attribute [r] threshold
14
- # @return [Numeric]
15
- #
16
- # @!attribute [r] window_size
17
- # @return [Numeric]
18
- #
19
- # @!attribute [r] tracked_errors
20
- # @return [Array<StandardError>]
21
- #
22
- # @!attribute [r] skipped_errors
23
- # @return [Array<Exception>]
24
- #
25
7
  # @api private
26
8
  Config = Data.define(
27
9
  :name,
@@ -30,29 +12,46 @@ module Stoplight
30
12
  :recovery_threshold,
31
13
  :window_size,
32
14
  :tracked_errors,
33
- :skipped_errors
34
- ) do
35
- class << self
36
- # Creates a new NULL configuration object.
37
- # @return [Stoplight::Domain::Config]
38
- def empty
39
- new(**members.map { |key| [key, nil] }.to_h)
40
- end
41
- end
42
-
43
- # Checks if the given error should be tracked
44
- #
45
- # @param error [#==] The error to check, e.g. an Exception, Class or Proc
46
- # @return [Boolean]
47
- def track_error?(error)
48
- skip = skipped_errors.any? { |klass| klass === error }
49
- track = tracked_errors.any? { |klass| klass === error }
50
-
51
- !skip && track
15
+ :skipped_errors,
16
+ :traffic_control,
17
+ :traffic_recovery,
18
+ :error_notifier,
19
+ :notifiers,
20
+ :data_store
21
+ )
22
+ class Config
23
+ def cool_off_time_in_milliseconds
24
+ (cool_off_time * 1_000).to_i
52
25
  end
53
26
 
54
- def cool_off_time_in_milliseconds
55
- cool_off_time * 1_000
27
+ def with(
28
+ name: T.undefined,
29
+ cool_off_time: T.undefined,
30
+ threshold: T.undefined,
31
+ recovery_threshold: T.undefined,
32
+ window_size: T.undefined,
33
+ skipped_errors: T.undefined,
34
+ tracked_errors: T.undefined,
35
+ traffic_control: T.undefined,
36
+ traffic_recovery: T.undefined,
37
+ error_notifier: T.undefined,
38
+ notifiers: T.undefined,
39
+ data_store: T.undefined
40
+ )
41
+ super(
42
+ name: name.is_a?(Undefined) ? self.name : name,
43
+ cool_off_time: cool_off_time.is_a?(Undefined) ? self.cool_off_time : cool_off_time,
44
+ threshold: threshold.is_a?(Undefined) ? self.threshold : threshold,
45
+ recovery_threshold: recovery_threshold.is_a?(Undefined) ? self.recovery_threshold : recovery_threshold,
46
+ window_size: window_size.is_a?(Undefined) ? self.window_size : window_size,
47
+ skipped_errors: skipped_errors.is_a?(Undefined) ? self.skipped_errors : skipped_errors,
48
+ tracked_errors: tracked_errors.is_a?(Undefined) ? self.tracked_errors : tracked_errors,
49
+ traffic_control: traffic_control.is_a?(Undefined) ? self.traffic_control : traffic_control,
50
+ traffic_recovery: traffic_recovery.is_a?(Undefined) ? self.traffic_recovery : traffic_recovery,
51
+ error_notifier: error_notifier.is_a?(Undefined) ? self.error_notifier : error_notifier,
52
+ notifiers: notifiers.is_a?(Undefined) ? self.notifiers : notifiers,
53
+ data_store: data_store.is_a?(Undefined) ? self.data_store : data_store,
54
+ )
56
55
  end
57
56
  end
58
57
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stoplight
4
+ module Domain
5
+ # Determines which errors should be traced
6
+ class ErrorTrackingPolicy
7
+ def initialize(tracked:, skipped:)
8
+ @tracked = tracked
9
+ @skipped = skipped
10
+ end
11
+
12
+ def track?(error)
13
+ !skipped?(error) && tracked?(error)
14
+ end
15
+
16
+ private
17
+
18
+ def skipped?(error)
19
+ @skipped.any? { |matcher| matcher === error }
20
+ end
21
+
22
+ def tracked?(error)
23
+ @tracked.any? { |matcher| matcher === error }
24
+ end
25
+ end
26
+ end
27
+ end
@@ -16,7 +16,7 @@ module Stoplight
16
16
 
17
17
  # @param error [Exception]
18
18
  # @return (see #initialize)
19
- def self.from_error(error, time: Time.now)
19
+ def self.from_error(error, time:)
20
20
  new(error.class.name, error.message, time)
21
21
  end
22
22
 
@@ -6,6 +6,7 @@ module Stoplight
6
6
  module Domain
7
7
  class Light
8
8
  # Implements light configuration behavior
9
+ # steep:ignore:start
9
10
  module ConfigurationBuilderInterface
10
11
  # Configures data store to be used with this circuit breaker
11
12
  #
@@ -229,6 +230,7 @@ module Stoplight
229
230
  with_without_warning(skipped_errors:)
230
231
  end
231
232
  end
233
+ # steep:ignore:end
232
234
  end
233
235
  end
234
236
  end
@@ -1,49 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "forwardable"
4
-
5
3
  module Stoplight
6
4
  module Domain
7
5
  #
8
6
  # @api private use +Stoplight()+ method instead
9
7
  class Light
10
- extend Forwardable
11
8
  include Common::Deprecations
12
- include ConfigurationBuilderInterface
13
-
14
- # @!attribute [r] config
15
- # @return [Stoplight::Domain::Config]
16
- # @api private
17
- attr_reader :config
18
-
19
- # @!attribute [r] name
20
- # The name of the light.
21
- # @return [String]
22
- def_delegator :config, :name
23
-
24
- # @!attribute [r] green_run_strategy
25
- # @return [Stoplight::Domain::Strategies::GreenRunStrategy]
26
- protected attr_reader :green_run_strategy
9
+ include ConfigurationBuilderInterface # steep:ignore
27
10
 
28
- # @!attribute [r] yellow_run_strategy
29
- # @return [Stoplight::Domain::Strategies::YellowRunStrategy]
30
- protected attr_reader :yellow_run_strategy
11
+ attr_reader :name
31
12
 
32
- # @!attribute [r] red_run_strategy
33
- # @return [Stoplight::Domain::Strategies::RedRunStrategy]
34
- protected attr_reader :red_run_strategy
13
+ attr_reader :green_run_strategy
14
+ attr_reader :yellow_run_strategy
15
+ attr_reader :red_run_strategy
16
+ attr_reader :factory
17
+ attr_reader :state_store
35
18
 
36
- # @!attribute [r] factory
37
- # @return [Stoplight::Domain::LightFactory]
38
- protected attr_reader :factory
39
-
40
- # @!attribute state_store
41
- # @param [Stoplight::Domain::Storage::State]
42
- protected attr_reader :state_store
43
-
44
- # @param config [Stoplight::Domain::Config]
45
- def initialize(config, green_run_strategy:, yellow_run_strategy:, red_run_strategy:, factory:, state_store:)
46
- @config = config
19
+ def initialize(name, green_run_strategy:, yellow_run_strategy:, red_run_strategy:, factory:, state_store:)
20
+ @name = name
47
21
  @green_run_strategy = green_run_strategy
48
22
  @yellow_run_strategy = yellow_run_strategy
49
23
  @red_run_strategy = red_run_strategy
@@ -56,7 +30,6 @@ module Stoplight
56
30
  # * +Stoplight::State::LOCKED_RED+ -- light is locked red and blocks all traffic
57
31
  # * +Stoplight::State::UNLOCKED+ -- light is not locked and follow the configured rules
58
32
  #
59
- # @return [String]
60
33
  def state = state_snapshot.locked_state
61
34
 
62
35
  # Returns current color:
@@ -68,7 +41,6 @@ module Stoplight
68
41
  # light = Stoplight('example')
69
42
  # light.color #=> Color::GREEN
70
43
  #
71
- # @return [String] returns current light color
72
44
  def color = state_snapshot.color
73
45
 
74
46
  # Runs the given block of code with this circuit breaker
@@ -81,9 +53,7 @@ module Stoplight
81
53
  # light = Stoplight('example')
82
54
  # light.run(->(error) { 0 }) { 1 / 0 } #=> 0
83
55
  #
84
- # @param fallback [Proc, nil] (nil) fallback code to run if the circuit breaker is open
85
- # @raise [Stoplight::Error::RedLight]
86
- # @return [any]
56
+ # @param fallback fallback code to run if the circuit breaker is open
87
57
  # @raise [Stoplight::Error::RedLight]
88
58
  def run(fallback = nil, &code)
89
59
  raise ArgumentError, "nothing to run. Please, pass a block into `Light#run`" unless block_given?
@@ -100,8 +70,8 @@ module Stoplight
100
70
  # light = Stoplight('example-locked')
101
71
  # light.lock(Stoplight::Color::RED)
102
72
  #
103
- # @param color [String] should be either +Color::RED+ or +Color::GREEN+
104
- # @return [Stoplight::Light] returns locked light (circuit breaker)
73
+ # @param color should be either +Color::RED+ or +Color::GREEN+
74
+ # @return locked light
105
75
  def lock(color)
106
76
  state = case color
107
77
  when Color::RED then State::LOCKED_RED
@@ -121,7 +91,7 @@ module Stoplight
121
91
  # light.lock(Stoplight::Color::RED)
122
92
  # light.unlock
123
93
  #
124
- # @return [Stoplight::Light] returns unlocked light (circuit breaker)
94
+ # @return returns unlocked light (circuit breaker)
125
95
  def unlock
126
96
  state_store.set_state(State::UNLOCKED)
127
97
 
@@ -129,9 +99,6 @@ module Stoplight
129
99
  end
130
100
 
131
101
  # Two lights considered equal if they have the same configuration.
132
- #
133
- # @param other [any]
134
- # @return [Boolean]
135
102
  def ==(other)
136
103
  other.is_a?(self.class) && factory == other.factory
137
104
  end
@@ -168,6 +135,7 @@ module Stoplight
168
135
  # payment_light.run(->(error) { nil }) { call_payment_api }
169
136
  # @deprecated
170
137
  # @see +Stoplight()+
138
+ # steep:ignore:start
171
139
  def with(**settings)
172
140
  deprecate(<<~MSG)
173
141
  Light#with is deprecated and will be removed in v6.0.0.
@@ -188,6 +156,7 @@ module Stoplight
188
156
  private def with_without_warning(**settings)
189
157
  factory.build_with(**settings)
190
158
  end
159
+ # steep:ignore:end
191
160
 
192
161
  private
193
162
 
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stoplight
4
+ module Domain
5
+ LightInfo = Data.define(:name)
6
+ end
7
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stoplight
4
+ module Domain
5
+ # Request metrics over a given window.
6
+ #
7
+ # @api private
8
+ MetricsSnapshot = Data.define(
9
+ :successes,
10
+ :errors,
11
+ :consecutive_errors,
12
+ :consecutive_successes,
13
+ :last_error,
14
+ :last_success_at
15
+ )
16
+
17
+ class MetricsSnapshot
18
+ # @!attribute successes
19
+ # A number of successes withing requested window. Zero for non-windowed metrics
20
+ #
21
+ # @!attribute errors
22
+ # A number of errors withing requested window. Zero for non-windowed metrics
23
+
24
+ # Calculates the error rate based on the number of successes and errors.
25
+ #
26
+ # @return [Float]
27
+ def error_rate
28
+ return unless requests # we effectively check if this is windowed metrics
29
+
30
+ if (successes! + errors!).zero?
31
+ 0.0
32
+ else
33
+ errors!.fdiv(successes! + errors!)
34
+ end
35
+ end
36
+
37
+ # @return [Integer]
38
+ def requests
39
+ if successes && errors # we effectively check if this is windowed metrics
40
+ successes! + errors!
41
+ end
42
+ end
43
+
44
+ # @return [Time, nil]
45
+ def last_error_at
46
+ last_error&.time
47
+ end
48
+
49
+ def successes!
50
+ successes or raise TypeError, "success must not be nil"
51
+ end
52
+
53
+ def errors!
54
+ errors or raise TypeError, "errors must not be nil"
55
+ end
56
+ end
57
+ end
58
+ end
@@ -2,39 +2,34 @@
2
2
 
3
3
  module Stoplight
4
4
  module Domain
5
- # @!attribute breached_at
6
- # The time when the light became red (breached threshold)
7
- # @return [Time, nil]
8
- #
9
- # @!attribute locked_state
10
- # @return [State::UNLOCKED | State::LOCKED_GREEN | State::LOCKED_RED]
11
- #
12
- # @!attribute recovery_scheduled_after
13
- # When Light transitions to RED, it schedules recovery after the Cool Off Time.
14
- # @return [Time, nil]
15
- #
16
- # @!attribute recovery_started_at
17
- # When in YELLOW state, this time indicates the time of transitioning to YELLOW
18
- # @return [Time, nil]
19
- #
20
- # @!attribute time
21
- # The time when the snapshot was taken
22
- # @return [Time]
23
- #
24
5
  StateSnapshot = Data.define(
25
6
  :breached_at,
26
7
  :locked_state,
27
8
  :recovery_scheduled_after,
28
9
  :recovery_started_at,
29
10
  :time
30
- ) do
11
+ )
12
+
13
+ class StateSnapshot
14
+ # @!attribute breached_at
15
+ # The time when the light became red (breached threshold)
16
+ #
17
+ # @!attribute recovery_scheduled_after
18
+ # When Light transitions to RED, it schedules recovery after the Cool Off Time.
19
+ #
20
+ # @!attribute recovery_started_at
21
+ # When in YELLOW state, this time indicates the time of transitioning to YELLOW
22
+ #
23
+ # @!attribute time
24
+ # The time when the snapshot was taken
25
+
31
26
  # @return [String] one of +Color::GREEN+, +Color::RED+, or +Color::YELLOW+
32
27
  def color
33
28
  if locked_state == State::LOCKED_GREEN
34
29
  Color::GREEN
35
30
  elsif locked_state == State::LOCKED_RED
36
31
  Color::RED
37
- elsif (recovery_scheduled_after && recovery_scheduled_after < time) || recovery_started_at
32
+ elsif (recovery_scheduled_after && recovery_scheduled_after! < time) || recovery_started_at
38
33
  Color::YELLOW
39
34
  elsif breached_at
40
35
  Color::RED
@@ -48,9 +43,20 @@ module Stoplight
48
43
  #
49
44
  # This method indicates whether the recovery has already started explicitly
50
45
  #
51
- # @return [Boolean]
52
46
  def recovery_started?
53
- recovery_started_at && recovery_started_at <= time
47
+ if recovery_started_at.nil?
48
+ false
49
+ else
50
+ recovery_started_at! <= time
51
+ end
52
+ end
53
+
54
+ def recovery_started_at!
55
+ recovery_started_at or raise TypeError, "recovery_started_at must not be nil"
56
+ end
57
+
58
+ def recovery_scheduled_after!
59
+ recovery_scheduled_after or raise TypeError, "recovery_scheduled_after must not be nil"
54
60
  end
55
61
  end
56
62
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stoplight
4
+ module Domain
5
+ module Storage
6
+ class RecoveryLockToken
7
+ attr_reader :token
8
+
9
+ def initialize
10
+ @token = SecureRandom.uuid
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -9,34 +9,26 @@ module Stoplight
9
9
  # by either raising them or invoking a fallback if provided.
10
10
  #
11
11
  # @api private
12
- class GreenRunStrategy < RunStrategy
13
- # @!attribute [r] request_tracker
14
- # @return [Stoplight::Domain::Tracker::Request]
15
- protected attr_reader :request_tracker
16
-
17
- # @!attribute [r] config
18
- # @return [Stoplight::Domain::Config] The configuration for the light.
19
- protected attr_reader :config
20
-
21
- # @param config [Stoplight::Domain::Config]
22
- # @param request_tracker [Stoplight::Domain::Tracker::Request
23
- def initialize(config:, request_tracker:)
24
- @config = config
12
+ class GreenRunStrategy
13
+ def initialize(error_tracking_policy:, request_tracker:)
14
+ @error_tracking_policy = error_tracking_policy
25
15
  @request_tracker = request_tracker
26
16
  end
27
17
 
28
18
  # Executes the provided code block when the light is in the green state.
29
19
  #
30
- # @param fallback [Proc, nil] A fallback proc to execute in case of an error.
31
- # @param state_snapshot [Stoplight::Domain::StateSnapshot]
20
+ # @param fallback A fallback proc to execute in case of an error.
21
+ # @param state_snapshot
32
22
  # @yield The code block to execute.
33
- # @return [Object] The result of the code block if successful.
34
- # @raise [Exception] Re-raises the error if it is not tracked or no fallback is provided.
23
+ # @return The result of the code block if successful.
24
+ # @raise re-raises the error if it is not tracked or no fallback is provided.
35
25
  def execute(fallback, state_snapshot:, &code)
36
26
  # TODO: Consider implementing sampling rate to limit the memory footprint
37
- code.call.tap { record_success }
27
+ result = code.call
28
+ record_success
29
+ result
38
30
  rescue => error
39
- if config.track_error?(error)
31
+ if @error_tracking_policy.track?(error)
40
32
  record_error(error)
41
33
 
42
34
  if fallback
@@ -51,18 +43,18 @@ module Stoplight
51
43
  end
52
44
  end
53
45
 
54
- private def record_error(error)
46
+ private
47
+
48
+ attr_reader :config
49
+ attr_reader :request_tracker
50
+
51
+ def record_error(error)
55
52
  request_tracker.record_failure(error)
56
53
  end
57
54
 
58
- private def record_success
55
+ def record_success
59
56
  request_tracker.record_success
60
57
  end
61
-
62
- # @return [Boolean]
63
- def ==(other)
64
- super && config == other.config && request_tracker == other.request_tracker
65
- end
66
58
  end
67
59
  end
68
60
  end
@@ -9,28 +9,25 @@ module Stoplight
9
9
  # or invokes a fallback if provided.
10
10
  #
11
11
  # @api private
12
- class RedRunStrategy < RunStrategy
13
- # @!attribute [r] config
14
- # @return [Stoplight::Domain::Config] The configuration for the light.
15
- protected attr_reader :config
16
-
17
- def initialize(config:)
18
- @config = config
12
+ class RedRunStrategy
13
+ def initialize(name:, cool_off_time:)
14
+ @name = name
15
+ @cool_off_time = cool_off_time
19
16
  end
20
17
 
21
18
  # Executes the fallback proc when the light is in the red state.
22
19
  #
23
- # @param fallback [Proc, nil] A fallback proc to execute instead of the code block.
24
- # @param state_snapshot [Stoplight::Domain::StateSnapshot]
25
- # @return [Object, nil] The result of the fallback proc if provided.
20
+ # @param fallback A fallback proc to execute instead of the code block.
21
+ # @param state_snapshot
22
+ # @return The result of the fallback proc if provided.
26
23
  # @raise [Stoplight::Error::RedLight] Raises an error if no fallback is provided.
27
24
  def execute(fallback, state_snapshot:)
28
25
  if fallback
29
26
  fallback.call(nil)
30
27
  else
31
28
  raise Error::RedLight.new(
32
- config.name,
33
- cool_off_time: config.cool_off_time,
29
+ @name,
30
+ cool_off_time: @cool_off_time,
34
31
  retry_after: state_snapshot.recovery_scheduled_after
35
32
  )
36
33
  end