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
@@ -10,22 +10,22 @@ module Stoplight
10
10
  # config = Stoplight::Domain::Config.new(threshold: 0.6, window_size: 300, traffic_control:)
11
11
  #
12
12
  # Will switch to red if 60% error rate reached within the 5-minute (300 seconds) sliding window.
13
- # By default this traffic control strategy starts evaluating only after 10 requests have been made. You can
14
- # adjust this by passing a different value for `min_requests` when initializing the strategy.
15
- #
16
- # traffic_control = Stoplight::Domain::TrafficControl::ErrorRate.new(min_requests: 100)
17
13
  #
18
14
  # @api private
19
15
  class ErrorRate
20
- # @param min_requests Minimum number of requests before traffic control is applied.
21
- # until this number of requests is reached, the error rate will not be considered.
22
- def initialize(min_requests: 10)
23
- @min_requests = min_requests
16
+ NAME = :error_rate
17
+
18
+ MIN_REQUESTS = 100
19
+ private_constant :MIN_REQUESTS
20
+
21
+ def initialize
24
22
  end
25
23
 
26
24
  def check_compatibility(config)
27
25
  if config.window_size.nil?
28
26
  CompatibilityResult.incompatible("`window_size` should be set")
27
+ elsif !config.threshold.is_a?(Numeric)
28
+ CompatibilityResult.incompatible("`threshold` should be a number")
29
29
  elsif config.threshold < 0 || config.threshold > 1
30
30
  CompatibilityResult.incompatible("`threshold` should be between 0 and 1")
31
31
  else
@@ -39,16 +39,20 @@ module Stoplight
39
39
 
40
40
  raise ArgumentError, "accepts only windowed metrics" if error_rate.nil? || requests.nil?
41
41
 
42
- requests >= min_requests && error_rate >= config.threshold
42
+ requests >= MIN_REQUESTS && error_rate >= config.threshold
43
43
  end
44
44
 
45
+ def name = NAME.to_s
46
+
45
47
  def ==(other)
46
- other.is_a?(self.class) && min_requests == other.min_requests
48
+ other.is_a?(self.class)
47
49
  end
48
50
 
49
- protected
51
+ def eql?(other)
52
+ self == other
53
+ end
50
54
 
51
- attr_reader :min_requests
55
+ def hash = self.class.hash
52
56
  end
53
57
  end
54
58
  end
@@ -34,11 +34,13 @@ module Stoplight
34
34
  #
35
35
  # @api private
36
36
  class ConsecutiveSuccesses
37
+ NAME = :consecutive_successes
38
+
37
39
  def check_compatibility(config)
38
- if config.recovery_threshold <= 0
39
- CompatibilityResult.incompatible("`recovery_threshold` should be bigger than 0")
40
- elsif !config.recovery_threshold.is_a?(Integer)
40
+ if !config.recovery_threshold.is_a?(Integer)
41
41
  CompatibilityResult.incompatible("`recovery_threshold` should be an integer")
42
+ elsif config.recovery_threshold <= 0
43
+ CompatibilityResult.incompatible("`recovery_threshold` should be bigger than 0")
42
44
  else
43
45
  CompatibilityResult.compatible
44
46
  end
@@ -55,7 +57,11 @@ module Stoplight
55
57
  end
56
58
  end
57
59
 
60
+ def hash = self.class.hash
61
+
58
62
  def ==(other) = other.is_a?(self.class)
63
+
64
+ def name = NAME.to_s
59
65
  end
60
66
  end
61
67
  end
@@ -5,13 +5,22 @@ module Stoplight
5
5
  class Base < StandardError
6
6
  end
7
7
 
8
+ class UnregisteredLightError < Base
9
+ end
10
+
8
11
  class ConfigurationError < Base
9
12
  end
10
13
 
11
14
  class IncorrectColor < Base
12
15
  end
13
16
 
17
+ class TooManySubscriptions < Base
18
+ end
19
+
14
20
  class RedLight < Base
21
+ EXCEPTION_MESSAGE = 'Stoplight "%{light_name}" is red - traffic stopped until recovery.'
22
+ private_constant :EXCEPTION_MESSAGE
23
+
15
24
  # @!attribute light_name
16
25
  # @return [String] The light's name
17
26
  attr_reader :light_name
@@ -39,7 +48,7 @@ module Stoplight
39
48
  @cool_off_time = cool_off_time
40
49
  @retry_after = retry_after
41
50
 
42
- super(light_name)
51
+ super(format(EXCEPTION_MESSAGE, light_name: light_name))
43
52
  end
44
53
  end
45
54
  end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stoplight
4
+ module Infrastructure
5
+ class ConfigSerializer
6
+ class << self
7
+ def call(config)
8
+ {
9
+ "id" => config.id,
10
+ "name" => config.name,
11
+ "cool_off_time" => config.cool_off_time,
12
+ "threshold" => config.threshold,
13
+ "recovery_threshold" => config.recovery_threshold,
14
+ "window_size" => config.window_size,
15
+ "tracked_errors" => config.tracked_errors.map(&:name),
16
+ "skipped_errors" => config.skipped_errors.map(&:name),
17
+ "traffic_control" => {
18
+ "strategy" => serialize_traffic_control(config.traffic_control)
19
+ },
20
+ "traffic_recovery" => {
21
+ "strategy" => serialize_traffic_recovery(config.traffic_recovery)
22
+ }
23
+ }
24
+ end
25
+
26
+ private
27
+
28
+ def serialize_traffic_control(traffic_control)
29
+ case traffic_control
30
+ when Domain::TrafficControl::ConsecutiveErrors
31
+ Domain::TrafficControl::ConsecutiveErrors::NAME.to_s
32
+ when Domain::TrafficControl::ErrorRate
33
+ Domain::TrafficControl::ErrorRate::NAME.to_s
34
+ else
35
+ raise TypeError, "unable to serialize traffic_control: #{traffic_control}"
36
+ end
37
+ end
38
+
39
+ def serialize_traffic_recovery(traffic_recovery)
40
+ case traffic_recovery
41
+ when Domain::TrafficRecovery::ConsecutiveSuccesses
42
+ Domain::TrafficRecovery::ConsecutiveSuccesses::NAME.to_s
43
+ else
44
+ raise TypeError, "unable to serialize traffic_recovery: #{traffic_recovery}"
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stoplight
4
+ module Infrastructure
5
+ module FailSafe
6
+ # Wraps a user-provided error notifier so a failure in the notifier itself
7
+ # cannot escape to callers of fail-safe components.
8
+ #
9
+ # @api private
10
+ class ErrorNotifier
11
+ attr_reader :error_notifier
12
+
13
+ def initialize(error_notifier:)
14
+ @error_notifier = error_notifier
15
+ end
16
+
17
+ def call(error)
18
+ error_notifier.call(error)
19
+ rescue => notifier_error
20
+ warn "Stoplight error_notifier raised: #{notifier_error.message}"
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stoplight
4
+ module Infrastructure
5
+ module FailSafe
6
+ module Storage
7
+ class Registry
8
+ def initialize(primary_registry:, error_notifier:, failover_registry:, circuit_breaker:)
9
+ @primary_registry = primary_registry
10
+ @error_notifier = error_notifier
11
+ @failover_registry = failover_registry
12
+ @circuit_breaker = circuit_breaker
13
+ end
14
+
15
+ def ids
16
+ fallback = ->(error) {
17
+ @error_notifier.call(error) if error
18
+ @failover_registry.ids
19
+ }
20
+ @circuit_breaker.run(fallback) do
21
+ @primary_registry.ids
22
+ end
23
+ end
24
+
25
+ def all_configs
26
+ fallback = ->(error) {
27
+ @error_notifier.call(error) if error
28
+ @failover_registry.all_configs
29
+ }
30
+ @circuit_breaker.run(fallback) do
31
+ @primary_registry.all_configs
32
+ end
33
+ end
34
+
35
+ def register(config)
36
+ fallback = ->(error) {
37
+ @error_notifier.call(error) if error
38
+ @failover_registry.register(config)
39
+ }
40
+ @circuit_breaker.run(fallback) do
41
+ @primary_registry.register(config)
42
+ end
43
+ end
44
+
45
+ def unregister(id)
46
+ fallback = ->(error) {
47
+ @error_notifier.call(error) if error
48
+ @failover_registry.unregister(id)
49
+ }
50
+ @circuit_breaker.run(fallback) do
51
+ @primary_registry.unregister(id)
52
+ end
53
+ end
54
+
55
+ def config_for(id)
56
+ fallback = ->(error) {
57
+ @error_notifier.call(error) if error
58
+ @failover_registry.config_for(id)
59
+ }
60
+ @circuit_breaker.run(fallback) do
61
+ @primary_registry.config_for(id)
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stoplight
4
+ module Infrastructure
5
+ module Memory
6
+ module Storage
7
+ class Registry
8
+ def ids = []
9
+ def all_configs = []
10
+
11
+ def register(config) = nil
12
+ def unregister(id) = nil
13
+ def config_for(id) = nil
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -28,64 +28,50 @@ module Stoplight
28
28
 
29
29
  # Get metrics for the current light
30
30
  def metrics_snapshot
31
- mutex.synchronize do
32
- Domain::MetricsSnapshot.new(
33
- errors: nil,
34
- successes: nil,
35
- consecutive_errors: consecutive_errors.to_i,
36
- consecutive_successes: consecutive_successes.to_i,
37
- last_error: last_error,
38
- last_success_at: last_success_at
39
- )
40
- end
31
+ @mutex.synchronize { build_metrics_snapshot }
41
32
  end
42
33
 
43
34
  # Records successful circuit breaker execution
44
35
  def record_success
45
- current_time = clock.current_time
36
+ current_time = @clock.current_time
46
37
 
47
- mutex.synchronize do
48
- if last_success_at.nil? || current_time > last_success_at
49
- self.last_success_at = current_time
38
+ @mutex.synchronize do
39
+ if @last_success_at.nil? || current_time > T.must(@last_success_at)
40
+ @last_success_at = current_time
50
41
  end
51
42
 
52
- self.consecutive_errors = 0
53
- self.consecutive_successes += 1
43
+ @consecutive_errors = 0
44
+ @consecutive_successes += 1
54
45
  end
55
46
  end
56
47
 
57
48
  # Records failed circuit breaker execution
58
49
  def record_failure(exception)
59
- current_time = clock.current_time
50
+ current_time = @clock.current_time
60
51
  failure = Domain::Failure.from_error(exception, time: current_time)
61
- last_error_at = self.last_error_at
62
52
 
63
- mutex.synchronize do
53
+ @mutex.synchronize do
54
+ last_error_at = self.last_error_at
55
+
64
56
  if last_error_at.nil? || failure.occurred_at > last_error_at
65
- self.last_error = failure
57
+ @last_error = failure
66
58
  end
67
59
 
68
- self.consecutive_errors += 1
69
- self.consecutive_successes = 0
60
+ @consecutive_errors += 1
61
+ @consecutive_successes = 0
62
+
63
+ build_metrics_snapshot
70
64
  end
71
65
  end
72
66
 
73
67
  def clear
74
- mutex.synchronize do
68
+ @mutex.synchronize do
75
69
  initialize_metrics
76
70
  end
77
71
  end
78
72
 
79
73
  private
80
74
 
81
- attr_accessor :consecutive_errors
82
- attr_accessor :consecutive_successes
83
- attr_accessor :last_error
84
- attr_accessor :last_success_at
85
-
86
- attr_reader :mutex
87
- attr_reader :clock
88
-
89
75
  def initialize_metrics
90
76
  @consecutive_errors = 0
91
77
  @consecutive_successes = 0
@@ -94,7 +80,18 @@ module Stoplight
94
80
  end
95
81
 
96
82
  def last_error_at
97
- last_error&.occurred_at
83
+ @last_error&.occurred_at
84
+ end
85
+
86
+ def build_metrics_snapshot
87
+ Domain::MetricsSnapshot.new(
88
+ errors: nil,
89
+ successes: nil,
90
+ consecutive_errors: @consecutive_errors,
91
+ consecutive_successes: @consecutive_successes,
92
+ last_error: @last_error,
93
+ last_success_at: @last_success_at
94
+ )
98
95
  end
99
96
  end
100
97
  end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stoplight
4
+ module Infrastructure
5
+ module Memory
6
+ module Storage
7
+ class WindowMetrics
8
+ # Hash-based sliding window for O(1) amortized operations.
9
+ #
10
+ # Maintains a running sum and stores per-second counts in a Hash. Ruby's Hash
11
+ # preserves insertion order (FIFO), allowing efficient removal of expired
12
+ # buckets from the front via +Hash#shift+, with their counts subtracted from
13
+ # the running sum.
14
+ #
15
+ # Performance: O(1) amortized for both reads and writes
16
+ # Memory: Bounded to the number of buckets
17
+ #
18
+ # @note Not thread-safe; synchronization must be handled externally
19
+ # @api private
20
+ class SlidingWindow
21
+ def initialize(clock:, window_size:)
22
+ # A hash mapping time buckets to their counts
23
+ @buckets = Hash.new { |buckets, bucket| buckets[bucket] = 0 }
24
+ # The running sum of all increments in the current window
25
+ @running_sum = 0
26
+ @evicted_through = nil
27
+ @clock = clock
28
+ @window_size = window_size
29
+ end
30
+
31
+ # Increment the count at the current monotonic second
32
+ def increment
33
+ timestamp = @clock.monotonic_seconds
34
+ slide_window!(timestamp - @window_size)
35
+ @buckets[timestamp.to_i] += 1
36
+ @running_sum += 1
37
+ end
38
+
39
+ def sum_in_window
40
+ slide_window!(@clock.monotonic_seconds - @window_size)
41
+ @running_sum
42
+ end
43
+
44
+ def inspect
45
+ "#<#{self.class.name} #{@buckets}>"
46
+ end
47
+
48
+ private
49
+
50
+ def slide_window!(window_start)
51
+ # A bucket is keyed at the second it was written, which for a whole-second window is
52
+ # always past the boundary in force then, so a boundary already evicted can expire
53
+ # nothing.
54
+ boundary = window_start.floor
55
+ return if boundary == @evicted_through
56
+
57
+ @evicted_through = boundary
58
+
59
+ loop do
60
+ timestamp, sum = @buckets.first
61
+ if timestamp.nil? || timestamp > boundary
62
+ break
63
+ else
64
+ @running_sum -= sum.to_i
65
+ @buckets.shift
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -27,28 +27,16 @@ module Stoplight
27
27
 
28
28
  # Get metrics for the current light
29
29
  def metrics_snapshot
30
- mutex.synchronize do
31
- window_start = (clock.current_time - @window_size)
32
- errors = @errors.sum_in_window(window_start)
33
- successes = @successes.sum_in_window(window_start)
34
-
35
- Domain::MetricsSnapshot.new(
36
- errors:,
37
- successes:,
38
- consecutive_errors: [@consecutive_errors, errors].min,
39
- consecutive_successes: [@consecutive_successes, successes].min,
40
- last_error: @last_error,
41
- last_success_at: @last_success_at
42
- )
43
- end
30
+ @mutex.synchronize { build_metrics_snapshot }
44
31
  end
45
32
 
46
33
  # Records successful circuit breaker execution
47
34
  def record_success
48
- mutex.synchronize do
49
- current_time = clock.current_time
35
+ @mutex.synchronize do
50
36
  @successes.increment
51
37
 
38
+ current_time = @clock.current_time
39
+
52
40
  if @last_success_at.nil? || current_time > T.must(@last_success_at)
53
41
  @last_success_at = current_time
54
42
  end
@@ -60,10 +48,10 @@ module Stoplight
60
48
 
61
49
  # Records failed circuit breaker execution
62
50
  def record_failure(exception)
63
- mutex.synchronize do
51
+ @mutex.synchronize do
64
52
  @errors.increment
65
53
 
66
- failure = Domain::Failure.from_error(exception, time: clock.current_time)
54
+ failure = Domain::Failure.from_error(exception, time: @clock.current_time)
67
55
  last_error_at = @last_error&.occurred_at
68
56
 
69
57
  if last_error_at.nil? || failure.occurred_at > last_error_at
@@ -72,27 +60,40 @@ module Stoplight
72
60
 
73
61
  @consecutive_errors += 1
74
62
  @consecutive_successes = 0
63
+
64
+ build_metrics_snapshot
75
65
  end
76
66
  end
77
67
 
78
68
  def clear
79
- mutex.synchronize do
69
+ @mutex.synchronize do
80
70
  initialize_metrics
81
71
  end
82
72
  end
83
73
 
84
74
  private
85
75
 
86
- attr_reader :mutex
87
- attr_reader :clock
88
-
89
76
  def initialize_metrics
90
77
  @consecutive_errors = 0
91
78
  @consecutive_successes = 0
92
79
  @last_error = nil
93
80
  @last_success_at = nil
94
- @successes = Infrastructure::Memory::DataStore::SlidingWindow.new(clock:)
95
- @errors = Infrastructure::Memory::DataStore::SlidingWindow.new(clock:)
81
+ @successes = SlidingWindow.new(clock: @clock, window_size: @window_size)
82
+ @errors = SlidingWindow.new(clock: @clock, window_size: @window_size)
83
+ end
84
+
85
+ def build_metrics_snapshot
86
+ errors = @errors.sum_in_window
87
+ successes = @successes.sum_in_window
88
+
89
+ Domain::MetricsSnapshot.new(
90
+ errors:,
91
+ successes:,
92
+ consecutive_errors: [@consecutive_errors, errors].min,
93
+ consecutive_successes: [@consecutive_successes, successes].min,
94
+ last_error: @last_error,
95
+ last_success_at: @last_success_at
96
+ )
96
97
  end
97
98
  end
98
99
  end
@@ -13,12 +13,14 @@ module Stoplight
13
13
  attr_reader :notifier
14
14
  # The underlying notifier being wrapped.
15
15
  attr_reader :error_notifier
16
+ attr_reader :circuit_breaker
16
17
 
17
18
  # @param notifier The notifier to wrap.
18
19
  # @param error_notifier called when wrapped data store fails
19
- def initialize(notifier:, error_notifier:)
20
+ def initialize(notifier:, error_notifier:, circuit_breaker:)
20
21
  @notifier = notifier
21
22
  @error_notifier = error_notifier
23
+ @circuit_breaker = circuit_breaker
22
24
  end
23
25
 
24
26
  # Sends a notification using the wrapped notifier with fail-safe mechanisms.
@@ -37,13 +39,6 @@ module Stoplight
37
39
  def ==(other)
38
40
  other.is_a?(self.class) && notifier == other.notifier
39
41
  end
40
-
41
- private def circuit_breaker
42
- @circuit_breaker ||= Stoplight.system_light(
43
- "stoplight:notifier:fail_safe:#{notifier.class.name}",
44
- notifiers: []
45
- )
46
- end
47
42
  end
48
43
  end
49
44
  end
@@ -8,7 +8,7 @@ module Stoplight
8
8
  #
9
9
  # @example Custom Notifier Implementation and Usage
10
10
  # # Custom notifier that writes notifications to a file
11
- # class FileNotifier < Stoplight::Domain::StateTransitionNotifier
11
+ # class FileNotifier
12
12
  # include Stoplight::Notifier::Generic
13
13
  #
14
14
  # def initialize(file_path)
@@ -69,11 +69,11 @@ module Stoplight
69
69
 
70
70
  # Processes the notification message.
71
71
  #
72
- # :nocov:
72
+ # simplecov:disable
73
73
  def put(message)
74
74
  raise NotImplementedError
75
75
  end
76
- # :nocov:
76
+ # simplecov:enable
77
77
  end
78
78
  end
79
79
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stoplight
4
+ module Infrastructure
5
+ module Redis
6
+ # Immutable key namespace for a light within a system.
7
+ #
8
+ # @example
9
+ # key_space #=> "stoplight:v6:df384ae97c77:{cfe6861fa39e}"
10
+ # key_space.join(:locks, :recovery) #=> "stoplight:v6:df384ae97c77:{cfe6861fa39e}:locks:recovery"
11
+ class Key < String
12
+ def initialize(*segments)
13
+ super(segments.join(":"))
14
+ freeze
15
+ end
16
+
17
+ # Builds a Redis key.
18
+ #
19
+ # @param segments to append
20
+ # @return Full Redis key
21
+ def join(*segments) = Key.new(self, *segments)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,9 @@
1
+ -- Returns current time in milliseconds since epoch.
2
+ -- In production: calls redis.call("TIME") for server time.
3
+ -- In tests: overridden with test double that reads from a Redis key.
4
+ local function now()
5
+ local time = redis.call("TIME")
6
+ local seconds = tonumber(time[1])
7
+ local microseconds = tonumber(time[2])
8
+ return seconds * 1000 + math.floor(microseconds / 1000)
9
+ end
@@ -39,11 +39,9 @@ module Stoplight
39
39
  recovery_lock if acquired
40
40
  end
41
41
 
42
- # @param recovery_lock [Stoplight::Infrastructure::Redis::DataStore::RecoveryLockToken]
43
- # @return [void]
44
42
  def release_lock(recovery_lock)
45
43
  scripting.call(
46
- :"recovery_lock/release_lock",
44
+ "recovery_lock/release_lock",
47
45
  keys: [lock_key], args: [recovery_lock.token]
48
46
  )
49
47
  end
@@ -55,7 +53,7 @@ module Stoplight
55
53
  attr_reader :scripting
56
54
  attr_reader :key_space
57
55
 
58
- def lock_key = key_space.key(:locks, :recovery)
56
+ def lock_key = key_space.join("locks", "recovery")
59
57
  def lock_timeout = config.cool_off_time_in_milliseconds
60
58
  end
61
59
  end
@@ -11,7 +11,7 @@ module Stoplight
11
11
  class RecoveryMetrics < UnboundedMetrics
12
12
  def initialize(redis:, scripting:, key_space:, clock:)
13
13
  super
14
- @metrics_key = key_space.key(:recovery_metrics)
14
+ @metrics_key = key_space.join("recovery_metrics")
15
15
  end
16
16
  end
17
17
  end