stoplight 5.8.3 → 6.0.0.rc2

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 (323) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -1
  3. data/LICENSE.md +1 -0
  4. data/README.md +132 -79
  5. data/UPGRADING.md +265 -6
  6. data/lib/stoplight/admin/actions/action.rb +4 -12
  7. data/lib/stoplight/admin/actions/lock.rb +12 -9
  8. data/lib/stoplight/admin/actions/lock_all.rb +27 -0
  9. data/lib/stoplight/admin/actions/remove.rb +12 -9
  10. data/lib/stoplight/admin/actions/stats.rb +15 -12
  11. data/lib/stoplight/admin/actions/unlock.rb +10 -9
  12. data/lib/stoplight/admin/assets/apple-touch-icon.png +0 -0
  13. data/lib/stoplight/admin/assets/favicon.ico +0 -0
  14. data/lib/stoplight/admin/assets/flowbite.min.css +2 -0
  15. data/lib/stoplight/admin/assets/flowbite.min.js +1 -0
  16. data/lib/stoplight/admin/assets/icon.svg +7 -0
  17. data/lib/stoplight/admin/assets/turbo.es2017-esm.min.js +34 -0
  18. data/lib/stoplight/admin/config_registry.rb +40 -0
  19. data/lib/stoplight/admin/dependencies.rb +29 -28
  20. data/lib/stoplight/admin/helpers.rb +50 -17
  21. data/lib/stoplight/admin/light_view.rb +184 -0
  22. data/lib/stoplight/admin/lights_stats.rb +7 -9
  23. data/lib/stoplight/admin/views/_card.erb +19 -21
  24. data/lib/stoplight/admin/views/index.erb +9 -3
  25. data/lib/stoplight/admin/views/layout.erb +45 -13
  26. data/lib/stoplight/admin.rb +110 -21
  27. data/lib/stoplight/data_store.rb +18 -8
  28. data/lib/stoplight/domain/config.rb +4 -1
  29. data/lib/stoplight/domain/error_tracking_policy.rb +9 -0
  30. data/lib/stoplight/domain/failure.rb +4 -0
  31. data/lib/stoplight/domain/id.rb +13 -0
  32. data/lib/stoplight/domain/light.rb +35 -77
  33. data/lib/stoplight/domain/lock_control.rb +55 -0
  34. data/lib/stoplight/domain/matcher_validator.rb +24 -0
  35. data/lib/stoplight/domain/state_snapshot.rb +2 -6
  36. data/lib/stoplight/domain/strategies/green_run_strategy.rb +33 -19
  37. data/lib/stoplight/domain/strategies/red_run_strategy.rb +8 -2
  38. data/lib/stoplight/domain/strategies/yellow_run_strategy.rb +56 -32
  39. data/lib/stoplight/domain/telemetry/bus.rb +90 -0
  40. data/lib/stoplight/domain/telemetry/consumer.rb +18 -0
  41. data/lib/stoplight/domain/telemetry/emitter.rb +45 -0
  42. data/lib/stoplight/domain/telemetry/envelope.rb +15 -0
  43. data/lib/stoplight/domain/telemetry/failure.rb +13 -0
  44. data/lib/stoplight/domain/telemetry/light_registered.rb +12 -0
  45. data/lib/stoplight/domain/telemetry/lock_changed.rb +19 -0
  46. data/lib/stoplight/domain/telemetry/metrics.rb +15 -0
  47. data/lib/stoplight/domain/telemetry/recovery_failed.rb +20 -0
  48. data/lib/stoplight/domain/telemetry/recovery_probe_completed.rb +15 -0
  49. data/lib/stoplight/domain/telemetry/recovery_started.rb +18 -0
  50. data/lib/stoplight/domain/telemetry/recovery_succeeded.rb +19 -0
  51. data/lib/stoplight/domain/telemetry/run_completed.rb +17 -0
  52. data/lib/stoplight/domain/telemetry/run_recorder.rb +58 -0
  53. data/lib/stoplight/domain/telemetry/settings.rb +21 -0
  54. data/lib/stoplight/domain/telemetry/state_transitioned.rb +11 -0
  55. data/lib/stoplight/domain/telemetry/subscription.rb +11 -0
  56. data/lib/stoplight/domain/telemetry/traffic_breached.rb +20 -0
  57. data/lib/stoplight/domain/tracker/recovery_probe.rb +61 -17
  58. data/lib/stoplight/domain/tracker/request.rb +17 -8
  59. data/lib/stoplight/domain/traffic_control/consecutive_errors.rb +13 -3
  60. data/lib/stoplight/domain/traffic_control/error_rate.rb +16 -12
  61. data/lib/stoplight/domain/traffic_recovery/consecutive_successes.rb +9 -3
  62. data/lib/stoplight/error.rb +10 -1
  63. data/lib/stoplight/infrastructure/config_serializer.rb +50 -0
  64. data/lib/stoplight/infrastructure/fail_safe/error_notifier.rb +25 -0
  65. data/lib/stoplight/infrastructure/fail_safe/storage/registry.rb +68 -0
  66. data/lib/stoplight/infrastructure/memory/storage/registry.rb +18 -0
  67. data/lib/stoplight/infrastructure/memory/storage/unbounded_metrics.rb +29 -32
  68. data/lib/stoplight/infrastructure/memory/storage/window_metrics/sliding_window.rb +74 -0
  69. data/lib/stoplight/infrastructure/memory/storage/window_metrics.rb +25 -24
  70. data/lib/stoplight/infrastructure/notifier/fail_safe.rb +3 -8
  71. data/lib/stoplight/infrastructure/notifier/generic.rb +3 -3
  72. data/lib/stoplight/infrastructure/redis/key.rb +25 -0
  73. data/lib/stoplight/infrastructure/redis/storage/now.lua +9 -0
  74. data/lib/stoplight/infrastructure/redis/storage/recovery_lock.rb +2 -4
  75. data/lib/stoplight/infrastructure/redis/storage/recovery_metrics.rb +1 -1
  76. data/lib/stoplight/infrastructure/redis/storage/registry.rb +73 -0
  77. data/lib/stoplight/infrastructure/redis/storage/scripting.rb +54 -3
  78. data/lib/stoplight/infrastructure/redis/storage/state/transition_to_green.lua +3 -1
  79. data/lib/stoplight/infrastructure/redis/storage/state/transition_to_red.lua +4 -2
  80. data/lib/stoplight/infrastructure/redis/storage/state/transition_to_yellow.lua +3 -1
  81. data/lib/stoplight/infrastructure/redis/storage/state.rb +8 -8
  82. data/lib/stoplight/infrastructure/redis/storage/unbounded_metrics/record_failure.lua +20 -21
  83. data/lib/stoplight/infrastructure/redis/storage/unbounded_metrics/record_success.lua +11 -19
  84. data/lib/stoplight/infrastructure/redis/storage/unbounded_metrics.rb +20 -16
  85. data/lib/stoplight/infrastructure/redis/storage/window_metrics/_evict.lua +44 -0
  86. data/lib/stoplight/infrastructure/redis/storage/window_metrics/metrics_snapshot.lua +14 -21
  87. data/lib/stoplight/infrastructure/redis/storage/window_metrics/record_failure.lua +38 -36
  88. data/lib/stoplight/infrastructure/redis/storage/window_metrics/record_success.lua +23 -30
  89. data/lib/stoplight/infrastructure/redis/storage/window_metrics.rb +45 -135
  90. data/lib/stoplight/infrastructure/system_clock.rb +4 -0
  91. data/lib/stoplight/telemetry.rb +19 -0
  92. data/lib/stoplight/types.rb +15 -2
  93. data/lib/stoplight/version.rb +1 -1
  94. data/lib/stoplight/wiring/config_compatibility_validator.rb +25 -2
  95. data/lib/stoplight/wiring/default.rb +1 -1
  96. data/lib/stoplight/wiring/default_config.rb +2 -1
  97. data/lib/stoplight/wiring/default_configuration.rb +3 -2
  98. data/lib/stoplight/wiring/external_caller.rb +27 -0
  99. data/lib/stoplight/wiring/fail_safe_config.rb +11 -0
  100. data/lib/stoplight/wiring/global_state.rb +93 -0
  101. data/lib/stoplight/wiring/{light_factory → light_configuration_dsl}/traffic_control_dsl.rb +3 -5
  102. data/lib/stoplight/wiring/{light_factory → light_configuration_dsl}/traffic_recovery_dsl.rb +2 -2
  103. data/lib/stoplight/wiring/light_configuration_dsl.rb +97 -0
  104. data/lib/stoplight/wiring/light_factory.rb +154 -97
  105. data/lib/stoplight/wiring/notifier_bridge.rb +33 -0
  106. data/lib/stoplight/wiring/redis/backend.rb +1 -1
  107. data/lib/stoplight/wiring/system/storage.rb +69 -0
  108. data/lib/stoplight/wiring/system.rb +125 -56
  109. data/lib/stoplight/wiring/{configuration_dsl.rb → system_configuration_dsl.rb} +13 -43
  110. data/lib/stoplight.rb +50 -194
  111. data/sig/sinatra/base.rbs +6 -0
  112. data/sig/stdlib/securerandom.rbs +4 -0
  113. data/sig/stoplight/admin/actions/action.rbs +10 -0
  114. data/sig/stoplight/admin/actions/lock.rbs +17 -0
  115. data/sig/stoplight/admin/actions/lock_all.rbs +17 -0
  116. data/sig/stoplight/admin/actions/remove.rbs +22 -0
  117. data/sig/stoplight/admin/actions/stats.rbs +28 -0
  118. data/sig/stoplight/admin/actions/unlock.rbs +17 -0
  119. data/sig/stoplight/admin/config_registry.rbs +20 -0
  120. data/sig/stoplight/admin/dependencies.rbs +16 -0
  121. data/sig/stoplight/admin/helpers.rbs +17 -0
  122. data/sig/stoplight/admin/light_view.rbs +39 -0
  123. data/sig/stoplight/admin/lights_stats.rbs +30 -0
  124. data/sig/stoplight/admin.rbs +14 -0
  125. data/sig/stoplight/color.rbs +3 -3
  126. data/sig/{_private/stoplight/data_store.rbs → stoplight/data_store/base.rbs} +1 -0
  127. data/sig/stoplight/data_store/memory.rbs +9 -0
  128. data/sig/stoplight/data_store/redis.rbs +17 -0
  129. data/sig/{_private/stoplight → stoplight}/domain/config.rbs +28 -24
  130. data/sig/{_private/stoplight → stoplight}/domain/error_tracking_policy.rbs +4 -0
  131. data/sig/{_private/stoplight → stoplight}/domain/failure.rbs +2 -0
  132. data/sig/stoplight/domain/id.rbs +7 -0
  133. data/sig/stoplight/domain/light.rbs +39 -0
  134. data/sig/{_private/stoplight → stoplight}/domain/light_info.rbs +1 -5
  135. data/sig/stoplight/domain/lock_control.rbs +16 -0
  136. data/sig/stoplight/domain/matcher_validator.rbs +11 -0
  137. data/sig/{_private/stoplight → stoplight}/domain/ports/clock.rbs +6 -0
  138. data/sig/stoplight/domain/ports/data_store.rbs +9 -0
  139. data/sig/stoplight/domain/ports/error_notifier.rbs +12 -0
  140. data/sig/stoplight/domain/ports/exception_matcher.rbs +10 -0
  141. data/sig/{_private/stoplight → stoplight}/domain/ports/metrics_store.rbs +2 -2
  142. data/sig/stoplight/domain/ports/registry.rbs +13 -0
  143. data/sig/{_private/stoplight → stoplight}/domain/ports/run_strategy.rbs +2 -1
  144. data/sig/stoplight/domain/ports/state_transition_notifier.rbs +18 -0
  145. data/sig/stoplight/domain/ports/telemetry.rbs +28 -0
  146. data/sig/stoplight/domain/ports/telemetry_publisher.rbs +14 -0
  147. data/sig/{_private/stoplight → stoplight}/domain/ports/traffic_control.rbs +7 -0
  148. data/sig/{_private/stoplight → stoplight}/domain/ports/traffic_recovery.rbs +2 -3
  149. data/sig/stoplight/domain/strategies/green_run_strategy.rbs +22 -0
  150. data/sig/stoplight/domain/strategies/red_run_strategy.rbs +19 -0
  151. data/sig/{_private/stoplight → stoplight}/domain/strategies/yellow_run_strategy.rbs +23 -12
  152. data/sig/stoplight/domain/telemetry/bus.rbs +49 -0
  153. data/sig/stoplight/domain/telemetry/consumer.rbs +13 -0
  154. data/sig/stoplight/domain/telemetry/emitter.rbs +51 -0
  155. data/sig/stoplight/domain/telemetry/envelope.rbs +30 -0
  156. data/sig/stoplight/domain/telemetry/failure.rbs +23 -0
  157. data/sig/stoplight/domain/telemetry/light_registered.rbs +23 -0
  158. data/sig/stoplight/domain/telemetry/lock_changed.rbs +31 -0
  159. data/sig/stoplight/domain/telemetry/metrics.rbs +27 -0
  160. data/sig/stoplight/domain/telemetry/recovery_failed.rbs +36 -0
  161. data/sig/stoplight/domain/telemetry/recovery_probe_completed.rbs +29 -0
  162. data/sig/stoplight/domain/telemetry/recovery_started.rbs +26 -0
  163. data/sig/stoplight/domain/telemetry/recovery_succeeded.rbs +31 -0
  164. data/sig/stoplight/domain/telemetry/run_completed.rbs +38 -0
  165. data/sig/stoplight/domain/telemetry/run_recorder.rbs +27 -0
  166. data/sig/stoplight/domain/telemetry/settings.rbs +47 -0
  167. data/sig/stoplight/domain/telemetry/state_transitioned.rbs +11 -0
  168. data/sig/stoplight/domain/telemetry/subscription.rbs +9 -0
  169. data/sig/stoplight/domain/telemetry/traffic_breached.rbs +36 -0
  170. data/sig/stoplight/domain/telemetry/types.rbs +32 -0
  171. data/sig/{_private/stoplight → stoplight}/domain/tracker/recovery_probe.rbs +10 -6
  172. data/sig/{_private/stoplight → stoplight}/domain/tracker/request.rbs +3 -3
  173. data/sig/{_private/stoplight → stoplight}/domain/traffic_control/consecutive_errors.rbs +2 -0
  174. data/sig/{_private/stoplight → stoplight}/domain/traffic_control/error_rate.rbs +3 -2
  175. data/sig/{_private/stoplight → stoplight}/domain/traffic_recovery/consecutive_successes.rbs +2 -0
  176. data/sig/stoplight/domain/types.rbs +25 -0
  177. data/sig/stoplight/error.rbs +8 -0
  178. data/sig/stoplight/generators/rails_generators_base.rbs +11 -0
  179. data/sig/stoplight/infrastructure/config_serializer.rbs +12 -0
  180. data/sig/stoplight/infrastructure/fail_safe/error_notifier.rbs +13 -0
  181. data/sig/{_private/stoplight → stoplight}/infrastructure/fail_safe/storage/metrics.rbs +2 -2
  182. data/sig/{_private/stoplight → stoplight}/infrastructure/fail_safe/storage/recovery_lock.rbs +2 -2
  183. data/sig/stoplight/infrastructure/fail_safe/storage/registry.rbs +23 -0
  184. data/sig/{_private/stoplight → stoplight}/infrastructure/fail_safe/storage/state.rbs +4 -4
  185. data/sig/stoplight/infrastructure/memory/storage/registry.rbs +13 -0
  186. data/sig/{_private/stoplight → stoplight}/infrastructure/memory/storage/state.rbs +3 -3
  187. data/sig/{_private/stoplight → stoplight}/infrastructure/memory/storage/unbounded_metrics.rbs +7 -7
  188. data/sig/stoplight/infrastructure/memory/storage/window_metrics/sliding_window.rbs +27 -0
  189. data/sig/{_private/stoplight → stoplight}/infrastructure/memory/storage/window_metrics.rbs +7 -7
  190. data/sig/stoplight/infrastructure/notifier/fail_safe.rbs +15 -0
  191. data/sig/{_private/stoplight → stoplight}/infrastructure/notifier/generic.rbs +1 -1
  192. data/sig/{_private/stoplight → stoplight}/infrastructure/notifier/io.rbs +1 -1
  193. data/sig/{_private/stoplight → stoplight}/infrastructure/notifier/logger.rbs +1 -1
  194. data/sig/stoplight/infrastructure/redis/key.rbs +10 -0
  195. data/sig/{_private/stoplight → stoplight}/infrastructure/redis/storage/recovery_lock.rbs +2 -2
  196. data/sig/stoplight/infrastructure/redis/storage/registry.rbs +27 -0
  197. data/sig/stoplight/infrastructure/redis/storage/scripting.rbs +34 -0
  198. data/sig/{_private/stoplight → stoplight}/infrastructure/redis/storage/state.rbs +4 -4
  199. data/sig/{_private/stoplight → stoplight}/infrastructure/redis/storage/unbounded_metrics.rbs +8 -1
  200. data/sig/stoplight/infrastructure/redis/storage/window_metrics.rbs +35 -0
  201. data/sig/stoplight/infrastructure/types.rbs +6 -0
  202. data/sig/stoplight/notifier.rbs +1 -1
  203. data/sig/stoplight/ports/system.rbs +16 -10
  204. data/sig/stoplight/state.rbs +3 -3
  205. data/sig/stoplight/telemetry.rbs +17 -0
  206. data/sig/stoplight/types.rbs +9 -0
  207. data/sig/{_private/stoplight → stoplight}/wiring/config_compatibility_validator.rbs +2 -0
  208. data/sig/stoplight/wiring/default.rbs +26 -0
  209. data/sig/stoplight/wiring/default_configuration.rbs +39 -0
  210. data/sig/stoplight/wiring/external_caller.rbs +13 -0
  211. data/sig/stoplight/wiring/fail_safe_config.rbs +7 -0
  212. data/sig/stoplight/wiring/global_state.rbs +36 -0
  213. data/sig/{_private/stoplight/wiring/light_factory → stoplight/wiring/light_configuration_dsl}/traffic_control_dsl.rbs +1 -1
  214. data/sig/{_private/stoplight/wiring/light_factory → stoplight/wiring/light_configuration_dsl}/traffic_recovery_dsl.rbs +1 -1
  215. data/sig/stoplight/wiring/light_configuration_dsl.rbs +38 -0
  216. data/sig/stoplight/wiring/light_factory.rbs +78 -0
  217. data/sig/stoplight/wiring/notifier_bridge.rbs +15 -0
  218. data/sig/stoplight/wiring/notifier_factory.rbs +10 -0
  219. data/sig/{_private/stoplight → stoplight}/wiring/redis/backend.rbs +6 -6
  220. data/sig/stoplight/wiring/system/storage.rbs +35 -0
  221. data/sig/stoplight/wiring/system.rbs +30 -0
  222. data/sig/stoplight/wiring/system_configuration_dsl.rbs +39 -0
  223. data/sig/stoplight/wiring/types.rbs +6 -0
  224. data/sig/stoplight.rbs +37 -54
  225. metadata +190 -143
  226. data/lib/stoplight/admin/actions/lock_all_green.rb +0 -18
  227. data/lib/stoplight/admin/actions/lock_green.rb +0 -23
  228. data/lib/stoplight/admin/actions/lock_red.rb +0 -23
  229. data/lib/stoplight/admin/lights_repository/light.rb +0 -171
  230. data/lib/stoplight/admin/lights_repository.rb +0 -87
  231. data/lib/stoplight/domain/light/configuration_builder_interface.rb +0 -236
  232. data/lib/stoplight/infrastructure/fail_safe/data_store.rb +0 -152
  233. data/lib/stoplight/infrastructure/memory/data_store/metrics.rb +0 -27
  234. data/lib/stoplight/infrastructure/memory/data_store/recovery_lock_store.rb +0 -52
  235. data/lib/stoplight/infrastructure/memory/data_store/recovery_lock_token.rb +0 -17
  236. data/lib/stoplight/infrastructure/memory/data_store/sliding_window.rb +0 -74
  237. data/lib/stoplight/infrastructure/memory/data_store/state.rb +0 -21
  238. data/lib/stoplight/infrastructure/memory/data_store.rb +0 -342
  239. data/lib/stoplight/infrastructure/redis/data_store/lua_scripts/get_metrics.lua +0 -26
  240. data/lib/stoplight/infrastructure/redis/data_store/lua_scripts/record_failure.lua +0 -36
  241. data/lib/stoplight/infrastructure/redis/data_store/lua_scripts/record_recovery_probe_failure.lua +0 -27
  242. data/lib/stoplight/infrastructure/redis/data_store/lua_scripts/record_recovery_probe_success.lua +0 -23
  243. data/lib/stoplight/infrastructure/redis/data_store/lua_scripts/record_success.lua +0 -35
  244. data/lib/stoplight/infrastructure/redis/data_store/lua_scripts/release_lock.lua +0 -6
  245. data/lib/stoplight/infrastructure/redis/data_store/lua_scripts/transition_to_green.lua +0 -10
  246. data/lib/stoplight/infrastructure/redis/data_store/lua_scripts/transition_to_red.lua +0 -10
  247. data/lib/stoplight/infrastructure/redis/data_store/lua_scripts/transition_to_yellow.lua +0 -9
  248. data/lib/stoplight/infrastructure/redis/data_store/recovery_lock_store.rb +0 -60
  249. data/lib/stoplight/infrastructure/redis/data_store/recovery_lock_token.rb +0 -28
  250. data/lib/stoplight/infrastructure/redis/data_store/scripting.rb +0 -73
  251. data/lib/stoplight/infrastructure/redis/data_store.rb +0 -516
  252. data/lib/stoplight/infrastructure/redis/storage/key_space.rb +0 -51
  253. data/lib/stoplight/infrastructure/storage/compatibility_metrics.rb +0 -41
  254. data/lib/stoplight/infrastructure/storage/compatibility_recovery_lock.rb +0 -33
  255. data/lib/stoplight/infrastructure/storage/compatibility_recovery_metrics.rb +0 -47
  256. data/lib/stoplight/infrastructure/storage/compatibility_state.rb +0 -44
  257. data/lib/stoplight/wiring/light_builder.rb +0 -198
  258. data/lib/stoplight/wiring/notifier_factory.rb +0 -26
  259. data/lib/stoplight/wiring/system/light_builder.rb +0 -47
  260. data/lib/stoplight/wiring/system/light_factory.rb +0 -64
  261. data/sig/_private/stoplight/domain/light.rbs +0 -25
  262. data/sig/_private/stoplight/domain/ports/data_store.rbs +0 -76
  263. data/sig/_private/stoplight/domain/ports/light_factory.rbs +0 -80
  264. data/sig/_private/stoplight/domain/strategies/green_run_strategy.rbs +0 -17
  265. data/sig/_private/stoplight/domain/strategies/red_run_strategy.rbs +0 -17
  266. data/sig/_private/stoplight/domain/tracker/base.rbs +0 -8
  267. data/sig/_private/stoplight/infrastructure/fail_safe/data_store.rbs +0 -26
  268. data/sig/_private/stoplight/infrastructure/memory/data_store/metrics.rbs +0 -25
  269. data/sig/_private/stoplight/infrastructure/memory/data_store/recovery_lock_store.rbs +0 -19
  270. data/sig/_private/stoplight/infrastructure/memory/data_store/recovery_lock_token.rbs +0 -17
  271. data/sig/_private/stoplight/infrastructure/memory/data_store/sliding_window.rbs +0 -27
  272. data/sig/_private/stoplight/infrastructure/memory/data_store/state.rbs +0 -17
  273. data/sig/_private/stoplight/infrastructure/memory/data_store.rbs +0 -30
  274. data/sig/_private/stoplight/infrastructure/notifier/fail_safe.rbs +0 -17
  275. data/sig/_private/stoplight/infrastructure/redis/data_store/recovery_lock_store.rbs +0 -24
  276. data/sig/_private/stoplight/infrastructure/redis/data_store/recovery_lock_token.rbs +0 -21
  277. data/sig/_private/stoplight/infrastructure/redis/data_store/scripting.rbs +0 -34
  278. data/sig/_private/stoplight/infrastructure/redis/data_store.rbs +0 -67
  279. data/sig/_private/stoplight/infrastructure/redis/storage/key_space.rbs +0 -19
  280. data/sig/_private/stoplight/infrastructure/redis/storage/scripting.rbs +0 -13
  281. data/sig/_private/stoplight/infrastructure/redis/storage/window_metrics.rbs +0 -34
  282. data/sig/_private/stoplight/infrastructure/storage/compatibility_metrics.rbs +0 -17
  283. data/sig/_private/stoplight/infrastructure/storage/compatibility_recovery_lock.rbs +0 -13
  284. data/sig/_private/stoplight/infrastructure/storage/compatibility_recovery_metrics.rbs +0 -14
  285. data/sig/_private/stoplight/infrastructure/storage/compatibility_state.rbs +0 -14
  286. data/sig/_private/stoplight/system/light_builder.rbs +0 -23
  287. data/sig/_private/stoplight/system/light_factory.rbs +0 -17
  288. data/sig/_private/stoplight/types.rbs +0 -6
  289. data/sig/_private/stoplight/wiring/configuration_dsl.rbs +0 -43
  290. data/sig/_private/stoplight/wiring/default.rbs +0 -26
  291. data/sig/_private/stoplight/wiring/default_configuration.rbs +0 -29
  292. data/sig/_private/stoplight/wiring/light_builder.rbs +0 -48
  293. data/sig/_private/stoplight/wiring/light_factory.rbs +0 -16
  294. data/sig/_private/stoplight/wiring/notifier_factory.rbs +0 -10
  295. data/sig/_private/stoplight/wiring/system.rbs +0 -15
  296. data/sig/_private/stoplight.rbs +0 -48
  297. data/sig/stoplight/data_store.rbs +0 -19
  298. data/sig/stoplight/ports/configuration.rbs +0 -19
  299. data/sig/stoplight/ports/exception_matcher.rbs +0 -8
  300. data/sig/stoplight/ports/light.rbs +0 -12
  301. data/sig/stoplight/ports/light_info.rbs +0 -5
  302. data/sig/stoplight/ports/state_transition_notifier.rbs +0 -15
  303. /data/sig/{_private/stoplight → stoplight}/common/deprecations.rbs +0 -0
  304. /data/sig/{_private/stoplight → stoplight}/domain/compatibility_result.rbs +0 -0
  305. /data/sig/{_private/stoplight → stoplight}/domain/metrics_snapshot.rbs +0 -0
  306. /data/sig/{_private/stoplight → stoplight}/domain/ports/recovery_lock_store.rbs +0 -0
  307. /data/sig/{_private/stoplight → stoplight}/domain/ports/recovery_lock_token.rbs +0 -0
  308. /data/sig/{_private/stoplight → stoplight}/domain/ports/state_store.rbs +0 -0
  309. /data/sig/{_private/stoplight → stoplight}/domain/state_snapshot.rbs +0 -0
  310. /data/sig/{_private/stoplight → stoplight}/domain/storage/recovery_lock_token.rbs +0 -0
  311. /data/sig/{_private/stoplight → stoplight}/domain/traffic_recovery.rbs +0 -0
  312. /data/sig/{_private → stoplight}/generators/stoplight/install/install_generator.rbs +0 -0
  313. /data/sig/{_private/stoplight → stoplight}/infrastructure/fail_safe/storage/recovery_lock_token.rbs +0 -0
  314. /data/sig/{_private/stoplight → stoplight}/infrastructure/memory/storage/recovery_lock.rbs +0 -0
  315. /data/sig/{_private/stoplight → stoplight}/infrastructure/memory/storage/recovery_metrics.rbs +0 -0
  316. /data/sig/{_private/stoplight → stoplight}/infrastructure/redis/storage/metrics.rbs +0 -0
  317. /data/sig/{_private/stoplight → stoplight}/infrastructure/redis/storage/recovery_metrics.rbs +0 -0
  318. /data/sig/{_private/stoplight → stoplight}/infrastructure/system_clock.rbs +0 -0
  319. /data/sig/{_private/stoplight → stoplight}/wiring/data_store_backend.rbs +0 -0
  320. /data/sig/{_private/stoplight → stoplight}/wiring/default_config.rbs +0 -0
  321. /data/sig/{_private/stoplight → stoplight}/wiring/memory/backend.rbs +0 -0
  322. /data/sig/{_private/stoplight → stoplight}/wiring/storage_set.rbs +0 -0
  323. /data/sig/{_private/stoplight → stoplight}/wiring/storage_set_builder.rbs +0 -0
@@ -2,126 +2,183 @@
2
2
 
3
3
  module Stoplight
4
4
  module Wiring
5
- # Concrete factory for building +Stoplight::Light++ instances with full dependency wiring.
5
+ # Wires together all infrastructure components (trackers, strategies, storage
6
+ # backend) needed for a functioning circuit breaker.
6
7
  #
7
- # This factory implements the +Stoplight::Domain::LightFactory+ protocol. It knows how to:
8
- # 1. Parse and transform user-provided settings
9
- # 2. Wire together all Light dependencies using a DI container
10
- # 3. Validate configuration compatibility
11
- # 4. Construct fully-functional Light instances
12
- #
13
- # @see Stoplight::Domain::LightFactory
14
- # @see Stoplight()
15
8
  # @api private
16
- #
17
9
  class LightFactory
18
- def initialize(config:)
10
+ def initialize(system_id:, system_name:, config:, failover_system:, telemetry:)
11
+ @system_id = system_id
12
+ @system_name = system_name
13
+ @failover_system = failover_system
19
14
  @config = config
15
+
16
+ @clock = Infrastructure::SystemClock.new
17
+ @name = T.must(config.name)
18
+ @cool_off_time = config.cool_off_time
19
+
20
+ @data_store_config = config.data_store
21
+ @error_notifier = Infrastructure::FailSafe::ErrorNotifier.new(
22
+ error_notifier: config.error_notifier
23
+ )
24
+ @traffic_recovery = config.traffic_recovery
25
+ @traffic_control = config.traffic_control
26
+
27
+ @error_tracking_policy = Domain::ErrorTrackingPolicy.new(
28
+ tracked: config.tracked_errors,
29
+ skipped: config.skipped_errors
30
+ )
31
+
32
+ @emitter = Domain::Telemetry::Emitter.new(
33
+ bus: telemetry,
34
+ system_name: @system_name,
35
+ light_name: config.name,
36
+ clock: @clock,
37
+ error_notifier: @error_notifier
38
+ )
20
39
  end
21
40
 
22
- def with(
23
- name: T.undefined,
24
- cool_off_time: T.undefined,
25
- threshold: T.undefined,
26
- recovery_threshold: T.undefined,
27
- window_size: T.undefined,
28
- tracked_errors: T.undefined,
29
- skipped_errors: T.undefined,
30
- data_store: T.undefined,
31
- error_notifier: T.undefined,
32
- notifiers: T.undefined,
33
- traffic_control: T.undefined,
34
- traffic_recovery: T.undefined
35
- )
36
- self.class.new(
37
- config: ConfigurationDsl.new(
38
- name:,
39
- cool_off_time:,
40
- threshold:,
41
- recovery_threshold:,
42
- window_size:,
43
- tracked_errors:,
44
- skipped_errors:,
45
- traffic_control:,
46
- traffic_recovery:,
47
- error_notifier:,
48
- data_store:,
49
- notifiers:
50
- ).configure!(config)
41
+ def build
42
+ light = Stoplight::Domain::Light.new(
43
+ @name,
44
+ state_store:,
45
+ green_run_strategy:,
46
+ yellow_run_strategy:,
47
+ red_run_strategy:,
48
+ lock_control:,
49
+ error_tracking_policy: @error_tracking_policy
51
50
  )
51
+
52
+ @emitter.emit(Domain::Telemetry::LightRegistered) do
53
+ Domain::Telemetry::LightRegistered.new(settings: telemetry_settings)
54
+ end
55
+
56
+ light
52
57
  end
53
58
 
54
- # Builds a fully-configured Light instance.
55
- #
56
- # The method resolves all dependencies from the container and constructs a Light that's
57
- # ready to use. The Light is injected with a reference to this factory, allowing the
58
- # +Stoplight::Light#with+ method to work for reconfiguration.
59
- #
60
- # @return [Stoplight::Light] Configured circuit breaker
61
- # @raise [Stoplight::Error::ConfigurationError] If configuration is invalid
62
- #
63
- # @example
64
- # factory = Stoplight::Wiring::LightFactory.new(container)
65
- # light = factory.build
66
- #
67
- # # Light is ready to use
68
- # light.run { api_call }
59
+ def state_store = storage_set.state_store
60
+ def metrics_store = storage_set.metrics_store
61
+ def lock_control = Domain::LockControl.new(state_store:, emitter: @emitter)
62
+ def recovery_metrics_store = storage_set.recovery_metrics_store
69
63
 
70
- def build
71
- light_builder(config:).build
64
+ private
65
+
66
+ attr_reader :data_store_config
67
+ attr_reader :error_notifier
68
+ attr_reader :clock
69
+ attr_reader :traffic_control
70
+ attr_reader :traffic_recovery
71
+ attr_reader :config
72
+ attr_reader :system_name
73
+
74
+ def recovery_lock_store = storage_set.recovery_lock_store
75
+ def storage_scripting = Infrastructure::Redis::Storage::Scripting.new(redis:)
76
+ def failover_system = T.must(@failover_system)
77
+
78
+ def key_space
79
+ @key_space ||= case data_store_config
80
+ when DataStore::Redis
81
+ # We use keys like +stoplight:version:system_id:{light_id}:metrics+ prefixes,
82
+ # Putting +liht_id+ into curly braces make it a Redis Cluster hash-tag - this is a segment
83
+ # for slot colocation.
84
+ data_store_config.key_space.join(@system_id, "{#{@config.id}}")
85
+ else
86
+ raise T.absurd(data_store_config)
87
+ end
72
88
  end
73
89
 
74
- def ==(other)
75
- other.is_a?(self.class) && other.config == config
90
+ def storage_set
91
+ @storage_set ||= StorageSetBuilder.new(backend: build_backend, windowed: !config.window_size.nil?).build
76
92
  end
77
93
 
78
- alias_method :eql?, :==
79
-
80
- def build_with(
81
- name: T.undefined,
82
- cool_off_time: T.undefined,
83
- threshold: T.undefined,
84
- recovery_threshold: T.undefined,
85
- window_size: T.undefined,
86
- tracked_errors: T.undefined,
87
- skipped_errors: T.undefined,
88
- data_store: T.undefined,
89
- error_notifier: T.undefined,
90
- notifiers: T.undefined,
91
- traffic_control: T.undefined,
92
- traffic_recovery: T.undefined
93
- )
94
- with(
95
- name:,
96
- cool_off_time:,
97
- threshold:,
98
- recovery_threshold:,
99
- window_size:,
100
- tracked_errors:,
101
- skipped_errors:,
102
- data_store:,
103
- error_notifier:,
104
- notifiers:,
105
- traffic_control:,
106
- traffic_recovery:
107
- ).build
94
+ def request_tracker
95
+ Domain::Tracker::Request.new(traffic_control:, config:, metrics_store:, state_store:, emitter: @emitter)
108
96
  end
109
97
 
110
- def hash
111
- [self.class, config].hash
98
+ def recovery_probe_tracker
99
+ Domain::Tracker::RecoveryProbe.new(
100
+ traffic_recovery:,
101
+ config:,
102
+ metrics_store: recovery_metrics_store,
103
+ state_store:,
104
+ emitter: @emitter
105
+ )
112
106
  end
113
107
 
114
- protected
108
+ def green_run_strategy
109
+ Domain::Strategies::GreenRunStrategy.new(
110
+ request_tracker:,
111
+ clock:,
112
+ run_recorder: run_recorder(Color::GREEN)
113
+ )
114
+ end
115
115
 
116
- attr_reader :config
116
+ def yellow_run_strategy
117
+ Domain::Strategies::YellowRunStrategy.new(
118
+ name: @name,
119
+ request_tracker: recovery_probe_tracker,
120
+ state_store:,
121
+ metrics_store:,
122
+ recovery_lock_store:,
123
+ config: @config,
124
+ clock:,
125
+ run_recorder: run_recorder(Color::YELLOW),
126
+ emitter: @emitter
127
+ )
128
+ end
117
129
 
118
- private
130
+ def red_run_strategy
131
+ Domain::Strategies::RedRunStrategy.new(
132
+ name: @name,
133
+ cool_off_time: @cool_off_time,
134
+ run_recorder: run_recorder(Color::RED)
135
+ )
136
+ end
119
137
 
120
- def light_builder(config:)
121
- LightBuilder.new(config:, factory: light_factory)
138
+ def run_recorder(color)
139
+ Domain::Telemetry::RunRecorder.new(emitter: @emitter, color:)
122
140
  end
123
141
 
124
- def light_factory = self
142
+ def telemetry_settings
143
+ Domain::Telemetry::Settings.new(
144
+ cool_off_time: @config.cool_off_time,
145
+ threshold: @config.threshold,
146
+ recovery_threshold: @config.recovery_threshold,
147
+ window_size: @config.window_size,
148
+ tracked_errors: @config.tracked_errors.map { |matcher| Domain::MatcherValidator.call(matcher) },
149
+ skipped_errors: @config.skipped_errors.map { |matcher| Domain::MatcherValidator.call(matcher) },
150
+ traffic_control: @config.traffic_control.name,
151
+ traffic_recovery: @config.traffic_recovery.name,
152
+ # No strategy accepts constructor params yet; placeholder for forward compatibility.
153
+ traffic_control_params: {},
154
+ traffic_recovery_params: {}
155
+ )
156
+ end
157
+
158
+ def redis
159
+ case data_store_config
160
+ when DataStore::Redis
161
+ data_store_config.redis
162
+ else
163
+ raise T.absurd(data_store_config)
164
+ end
165
+ end
166
+
167
+ def build_backend
168
+ case data_store_config
169
+ in DataStore::Memory
170
+ Memory::Backend.new(clock:, config:)
171
+ in DataStore::Redis
172
+ Redis::Backend.new(
173
+ redis:, scripting: storage_scripting, key_space:, clock:, config:, error_notifier:,
174
+ failover_light: create_circuit_breaker("redis")
175
+ )
176
+ end
177
+ end
178
+
179
+ def create_circuit_breaker(name)
180
+ failover_system.register(name)
181
+ end
125
182
  end
126
183
  end
127
184
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stoplight
4
+ module Wiring
5
+ # Subscribes the legacy, user-facing +Notifier+ collaborators to the telemetry bus, so
6
+ # +Domain::Light+'s collaborators never call notifiers directly.
7
+ #
8
+ # @api private
9
+ class NotifierBridge
10
+ def initialize(notifiers:)
11
+ @notifiers = notifiers
12
+ end
13
+
14
+ def subscribe(bus)
15
+ bus.subscribe(Domain::Telemetry::TrafficBreached) { |envelope| notify(envelope, error: envelope.payload.failure&.exception) }
16
+ bus.subscribe(Domain::Telemetry::RecoveryStarted) { |envelope| notify(envelope, error: nil) }
17
+ bus.subscribe(Domain::Telemetry::RecoverySucceeded) { |envelope| notify(envelope, error: nil) }
18
+ bus.subscribe(Domain::Telemetry::RecoveryFailed) { |envelope| notify(envelope, error: envelope.payload.failure&.exception) }
19
+ end
20
+
21
+ private
22
+
23
+ def notify(envelope, error:)
24
+ info = Domain::LightInfo.new(name: envelope.light_name)
25
+ payload = envelope.payload
26
+
27
+ @notifiers.each do |notifier|
28
+ notifier.notify(info, payload.from_color, payload.to_color, error)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -17,7 +17,7 @@ module Stoplight
17
17
  # backend = Redis::Backend.new(
18
18
  # redis: redis_connection,
19
19
  # scripting: Scripting.new(redis:),
20
- # key_space: KeySpace.build(system_name: "payments", light_name: "stripe"),
20
+ # key_space:,
21
21
  # config: light_config,
22
22
  # error_notifier: ->(e) { Logger.error(e) },
23
23
  # failover_light: Stoplight("redis-failover"),
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stoplight
4
+ module Wiring
5
+ class System
6
+ # Only for admin panel use.
7
+ class Storage
8
+ def initialize(system_id:, system_name:, failover_system:, telemetry:)
9
+ @system_id = system_id
10
+ @system_name = system_name
11
+ @failover_system = failover_system
12
+ @factories = {}
13
+ @telemetry = telemetry
14
+ end
15
+
16
+ def recovery_metrics_snapshot(config)
17
+ recovery_metrics_store(config).metrics_snapshot
18
+ end
19
+
20
+ def state_snapshot(config)
21
+ state_store(config).state_snapshot
22
+ end
23
+
24
+ def metrics_snapshot(config)
25
+ metrics_store(config).metrics_snapshot
26
+ end
27
+
28
+ def delete(config)
29
+ state_store(config).clear
30
+ metrics_store(config).clear
31
+ end
32
+
33
+ def lock(config, color)
34
+ lock_control(config).lock(color)
35
+ end
36
+
37
+ def unlock(config)
38
+ lock_control(config).unlock
39
+ end
40
+
41
+ private def recovery_metrics_store(config)
42
+ light_factory(config).recovery_metrics_store
43
+ end
44
+
45
+ private def state_store(config)
46
+ light_factory(config).state_store
47
+ end
48
+
49
+ private def metrics_store(config)
50
+ light_factory(config).metrics_store
51
+ end
52
+
53
+ private def lock_control(config)
54
+ light_factory(config).lock_control
55
+ end
56
+
57
+ private def light_factory(config)
58
+ @factories[config] ||= LightFactory.new(
59
+ system_id: @system_id,
60
+ system_name: @system_name,
61
+ config:,
62
+ failover_system: @failover_system,
63
+ telemetry: @telemetry
64
+ )
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -4,7 +4,6 @@ require "concurrent/map"
4
4
 
5
5
  module Stoplight
6
6
  module Wiring
7
- # 🚧UNDER CONSTRUCTION 🚧
8
7
  # System provides namespace isolation and shared configuration for related circuits.
9
8
  #
10
9
  # Systems enforce configuration consistency within their scope - creating the same
@@ -13,71 +12,97 @@ module Stoplight
13
12
  # This prevents subtle bugs where circuits silently interfere with each other.
14
13
  #
15
14
  # @example Basic usage
16
- # billing = Stoplight.system(:billing,
15
+ # billing = Stoplight.register_system(
16
+ # "Billing",
17
17
  # data_store: billing_redis,
18
18
  # threshold: 5,
19
19
  # window_size: 300
20
20
  # )
21
21
  #
22
- # billing.light("stripe")
23
- # billing.light("paypal")
22
+ # billing.register("stripe")
23
+ # billing.register("paypal")
24
+ #
25
+ # billing.light("stripe").run { ... }
26
+ # billing.light("paypal").run { ... }
24
27
  #
25
28
  # @example Multi-tenancy
26
- # tenant_a = Stoplight.system(:tenant_a, data_store: tenant_a_redis)
27
- # tenant_b = Stoplight.system(:tenant_b, data_store: tenant_b_redis)
29
+ # tenant_a = Stoplight.register_system("Tenant A", data_store: tenant_a_redis)
30
+ # tenant_b = Stoplight.register_system("Tenant B", data_store: tenant_b_redis)
28
31
  #
29
32
  # # Same circuit name, completely isolated
30
- # tenant_a.light("api")
31
- # tenant_b.light("api")
33
+ # tenant_a.register("api")
34
+ # tenant_b.register("api")
32
35
  #
33
36
  # @example Configuration inheritance
34
- # system = Stoplight.system(:payments, threshold: 3, cool_off_time: 600)
35
- #
36
- # system.light("stripe") # Inherits threshold: 3
37
- # system.light("paypal", threshold: 5) # Overrides threshold
37
+ # system = Stoplight.register_system("Payments", threshold: 3, cool_off_time: 600)
38
38
  #
39
- # @note System configuration objects (data_store, notifiers) should be defined
40
- # as constants and reused, not created inline. This ensures configuration
41
- # matching works correctly across multiple system references.
39
+ # system.register("stripe") # Inherits threshold: 3
40
+ # system.register("paypal", threshold: 5) # Overrides threshold
42
41
  #
43
- # @note Light instances are cached within the system. Calling {#light} with
44
- # the same name returns the cached instance.
45
- #
46
- # @api private
42
+ # @note Light instances are cached within the system once {#register}ed. {#light}
43
+ # returns that cached instance and raises +Stoplight::Error::UnregisteredLightError+
44
+ # if the name was never registered.
47
45
  class System
46
+ REGISTRATION_FRAME_LIMIT = 5
47
+ private_constant :REGISTRATION_FRAME_LIMIT
48
+
48
49
  attr_reader :name
49
- # @!attribute system_config
50
- # @api private
51
- attr_reader :system_config
50
+ # @api private
51
+ attr_reader :config
52
52
 
53
- def initialize(config:)
53
+ # Returns the consumer (subscribe-only) side of the telemetry bus.
54
+ def telemetry
55
+ Domain::Telemetry::Consumer.new(@telemetry)
56
+ end
57
+
58
+ # @param failover_system is a system used to create lights that protects components
59
+ # of this system. For example if your system uses Redis data store, or notifiers that
60
+ # communicate with external systems, they could go off. Failover system hosts
61
+ # all the circuit breakers that are needed to protect these dependencies from failing.
62
+ # Failover system itself never uses external dependencies and therefore does not need
63
+ # external failover.
64
+ def initialize(config:, failover_system:, registry:)
54
65
  @name = config.name
55
- @system_config = config
66
+ @config = config
56
67
  @lights = Concurrent::Map.new
68
+ @failover_system = failover_system
69
+ @registry = registry
70
+ @telemetry = Domain::Telemetry::Bus.new(error_notifier: config.error_notifier)
71
+
72
+ unless config.notifiers.empty?
73
+ NotifierBridge.new(notifiers: wrapped_notifiers).subscribe(@telemetry)
74
+ end
57
75
  end
58
76
 
59
- # Creates or retrieves a light.
77
+ def persistent?
78
+ case @config.data_store
79
+ when DataStore::Redis
80
+ true
81
+ when DataStore::Memory
82
+ false
83
+ else
84
+ raise T.absurd(@config.data_store)
85
+ end
86
+ end
87
+
88
+ # Registers and returns a light.
60
89
  #
61
- # If a light with this name already exists, returns the cached instance.
90
+ # If a light with this name already exists, returns it.
62
91
  # If settings differ from the existing light, raises +Stoplight::Error::ConfigurationError+.
63
92
  #
64
- #
65
93
  # @raise [Stoplight::Error::ConfigurationError] if light exists with different settings
66
94
  #
67
- # @example Create a light
68
- # light = system.light("stripe", threshold: 5, window_size: 60)
69
- #
70
- # @example Retrieve existing light - both return cached light
71
- # light = system.light("stripe", threshold: 5, window_size: 60)
72
- # light = system.light("stripe")
95
+ # @example Register a light
96
+ # system.register("stripe", threshold: 5, window_size: 60)
97
+ # system.light("stripe") #=> returns named light
73
98
  #
74
99
  # @example Configuration conflict
75
- # system.light("api", threshold: 5)
76
- # system.light("api", threshold: 10) # Raises ConfigurationError
100
+ # system.register("api", threshold: 5)
101
+ # system.register("api", threshold: 10) # Raises ConfigurationError
77
102
  #
78
103
  # @note Thread-safe: multiple threads can safely call this method concurrently
79
104
  #
80
- def light(
105
+ def register(
81
106
  name,
82
107
  cool_off_time: T.undefined,
83
108
  threshold: T.undefined,
@@ -88,7 +113,7 @@ module Stoplight
88
113
  traffic_control: T.undefined,
89
114
  traffic_recovery: T.undefined
90
115
  )
91
- light_config = ConfigurationDsl.new(
116
+ light_dsl = LightConfigurationDsl.new(
92
117
  name:,
93
118
  cool_off_time:,
94
119
  threshold:,
@@ -98,32 +123,76 @@ module Stoplight
98
123
  skipped_errors:,
99
124
  traffic_control:,
100
125
  traffic_recovery:
101
- ).configure!(system_config)
102
-
103
- light, _ = lights.compute(name) do |existing|
104
- if existing
105
- existing_light, existing_config = existing
106
- if light_config == existing_config
107
- [existing_light, existing_config]
108
- else
109
- raise Stoplight::Error::ConfigurationError, <<~MSG
110
- Light name `#{name}` reused with different settings:
111
- existing settings: #{existing_config}
112
- new settings: #{light_config}
113
-
114
- You cannot use the same light name with different settings.
115
- MSG
116
- end
117
- else
118
- [LightFactory.new(system: self, config: light_config).build, light_config]
126
+ )
127
+ config_digest = light_dsl.digest
128
+
129
+ light, existing_digest, existing_backtrace = @lights[name] || begin
130
+ registered_at = ExternalCaller.backtrace.first(REGISTRATION_FRAME_LIMIT)
131
+ config = light_dsl.configure!(@config)
132
+ @lights.compute_if_absent(name) do
133
+ built = LightFactory.new(
134
+ system_id: @config.id,
135
+ system_name: @name, config:,
136
+ failover_system: @failover_system,
137
+ telemetry: @telemetry
138
+ ).build
139
+ @registry.register(config)
140
+ [built, config_digest, registered_at]
119
141
  end
120
142
  end
143
+
144
+ if config_digest != existing_digest
145
+ original_site = existing_backtrace.map { |frame| " #{frame}" }.join("\n")
146
+
147
+ raise Stoplight::Error::ConfigurationError, <<~MSG, ExternalCaller.backtrace
148
+ Light `#{name}` already registered with different configuration.
149
+
150
+ Originally registered at:
151
+ #{original_site}
152
+
153
+ Lights must have consistent configuration across all call sites.
154
+ MSG
155
+ end
156
+
121
157
  light
122
158
  end
123
159
 
160
+ # @raise [Stoplight::Error::UnregisteredLightError] if no light was registered under +name+
161
+ def light(name)
162
+ @lights[name]&.first || raise(Stoplight::Error::UnregisteredLightError, <<~MSG)
163
+ Light `#{name}` was never registered on system `#{@name}`.
164
+ Call `.register(#{name.inspect}, ...)` at boot before using it.
165
+ MSG
166
+ end
167
+
168
+ # @api private
169
+ def __stoplight__storage
170
+ Storage.new(
171
+ system_id: @config.id,
172
+ system_name: @name,
173
+ failover_system: T.must(@failover_system), # works only with redis ds
174
+ telemetry: @telemetry
175
+ )
176
+ end
177
+
178
+ # @api private
179
+ def __stoplight__registry
180
+ @registry
181
+ end
182
+
124
183
  private
125
184
 
126
- attr_reader :lights
185
+ def wrapped_notifiers
186
+ error_notifier = Infrastructure::FailSafe::ErrorNotifier.new(error_notifier: @config.error_notifier)
187
+
188
+ @config.notifiers.map do |notifier|
189
+ Infrastructure::Notifier::FailSafe.new(
190
+ notifier:,
191
+ error_notifier:,
192
+ circuit_breaker: T.must(@failover_system).register("notifier:#{notifier.class.name}")
193
+ )
194
+ end
195
+ end
127
196
  end
128
197
  end
129
198
  end