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
@@ -1,9 +0,0 @@
1
- local meta_key = KEYS[1]
2
- local current_ts = tonumber(ARGV[1])
3
-
4
- -- HSETNX returns 1 if field is new and was set, 0 if field already exists
5
- local became_yellow = redis.call('HSETNX', meta_key, 'recovery_started_at', current_ts)
6
- if became_yellow == 1 then
7
- redis.call('HDEL', meta_key, 'recovery_scheduled_after', 'breached_at', 'recovered_at')
8
- end
9
- return became_yellow
@@ -1,60 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "securerandom"
4
- require "forwardable"
5
-
6
- module Stoplight
7
- module Infrastructure
8
- module Redis
9
- class DataStore
10
- # Distributed recovery lock using Redis SET NX (set-if-not-exists).
11
- #
12
- # Lock Acquisition:
13
- # - Uses unique UUID token to prevent accidental release of others' locks
14
- # - Atomic SET with NX flag ensures only one process acquires recovery_lock
15
- # - TTL (px: lock_timeout) auto-releases recovery_lock if process crashes
16
- #
17
- # Lock Release:
18
- # - Lua script ensures only token holder can release (token comparison)
19
- # - Best-effort release; TTL cleanup handles failures
20
- #
21
- # Failure Modes:
22
- # - Lock contention: Returns false, caller should skip probe
23
- # - Redis unavailable: raises an error and let caller decide
24
- # - Crashed holder: raises an error and let caller decide. Lock auto-expires after lock_timeout
25
- # - Release failure: Lock auto-expires after lock_timeout
26
- #
27
- class RecoveryLockStore
28
- def initialize(redis:, lock_timeout:, scripting:)
29
- @redis = redis
30
- @lock_timeout = lock_timeout
31
- @scripting = scripting
32
- end
33
-
34
- def acquire_lock(light_name)
35
- recovery_lock = RecoveryLockToken.new(light_name:)
36
-
37
- acquired = !!redis.then do |client|
38
- client.set(recovery_lock.lock_key, recovery_lock.token, nx: true, px: lock_timeout)
39
- end
40
-
41
- recovery_lock if acquired
42
- end
43
-
44
- def release_lock(recovery_lock)
45
- scripting.call(
46
- :release_lock,
47
- keys: [recovery_lock.lock_key], args: [recovery_lock.token]
48
- )
49
- end
50
-
51
- protected
52
-
53
- attr_reader :redis
54
- attr_reader :lock_timeout
55
- attr_reader :scripting
56
- end
57
- end
58
- end
59
- end
60
- end
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "securerandom"
4
-
5
- module Stoplight
6
- module Infrastructure
7
- module Redis
8
- class DataStore
9
- class RecoveryLockToken
10
- attr_reader :light_name
11
- attr_reader :token
12
-
13
- # @param light_name [String]
14
- def initialize(light_name:)
15
- @light_name = light_name
16
- @token = SecureRandom.uuid
17
- end
18
-
19
- def lock_key = key(:locks, :recovery, light_name)
20
-
21
- private def key(*parts)
22
- Stoplight::Infrastructure::Redis::DataStore.key(*parts)
23
- end
24
- end
25
- end
26
- end
27
- end
28
- end
@@ -1,73 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Stoplight
4
- module Infrastructure
5
- module Redis
6
- class DataStore
7
- # Manages Lua scripts for Redis operations.
8
- #
9
- # This class provides execution of Lua scripts by caching their SHA digests
10
- # and automatically reloading scripts if they're evicted from Redis memory.
11
- #
12
- # @example
13
- # script_manager = ScriptManager.new(redis: redis_client)
14
- # script_manager.call(:increment_counter, keys: ["counter:1"], args: [5])
15
- #
16
- # @note Scripts are loaded lazily on first use and cached in memory
17
- # @note Script files must be named `<script_name>.lua` and located in scripts_root
18
- class Scripting
19
- current_dir = __dir__ or raise "Cannot determine script directory"
20
- SCRIPTS_ROOT = File.join(current_dir, "lua_scripts")
21
- private_constant :SCRIPTS_ROOT
22
-
23
- class << self
24
- def default_scripts_root = SCRIPTS_ROOT
25
- end
26
-
27
- def initialize(redis:, scripts_root: self.class.default_scripts_root)
28
- @scripts_root = scripts_root
29
- @redis = redis
30
- @shas = {}
31
- end
32
-
33
- def call(script_name, keys: [], args: [])
34
- redis.then do |client|
35
- client.evalsha(script_sha(script_name), keys: keys.map(&:to_s), argv: args.map(&:to_s))
36
- end
37
- rescue ::Redis::CommandError => error
38
- if error.message.include?("NOSCRIPT")
39
- reload_script(script_name)
40
- retry
41
- else
42
- raise
43
- end
44
- end
45
-
46
- protected
47
-
48
- attr_reader :scripts_root
49
- attr_reader :redis
50
-
51
- private
52
-
53
- attr_reader :shas
54
-
55
- def reload_script(script_name)
56
- shas.delete(script_name)
57
- script_sha(script_name)
58
- end
59
-
60
- def script_sha(script_name)
61
- if shas.key?(script_name)
62
- shas[script_name]
63
- else
64
- script = File.read(File.join(scripts_root, "#{script_name}.lua"))
65
-
66
- shas[script_name] = redis.then { |client| client.script(:load, script) }
67
- end
68
- end
69
- end
70
- end
71
- end
72
- end
73
- end
@@ -1,516 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "forwardable"
4
-
5
- module Stoplight
6
- module Infrastructure
7
- module Redis
8
- # == Errors
9
- # All errors are stored in the sorted set where keys are serialized errors and
10
- # values (Redis uses "score" term) contain integer representations of the time
11
- # when an error happened.
12
- #
13
- # This data structure enables us to query errors that happened within a specific
14
- # period. We use this feature to support +window_size+ option.
15
- #
16
- # To avoid uncontrolled memory consumption, we keep at most +config.threshold+ number
17
- # of errors happened within last +config.window_size+ seconds (by default infinity).
18
- #
19
- # @see Base
20
- # steep:ignore:start
21
- class DataStore
22
- extend Forwardable
23
-
24
- class << self
25
- # Generates a Redis key by joining the prefix with the provided pieces.
26
- #
27
- # @param pieces [Array<String, Integer>] Parts of the key to be joined.
28
- # @return [String] The generated Redis key.
29
- # @api private
30
- def key(*pieces)
31
- [KEY_PREFIX, *pieces].join(KEY_SEPARATOR)
32
- end
33
-
34
- METRICS_RETENTION_TIME = 60 * 60 * 24 # 1 day
35
-
36
- # Retrieves the list of Redis bucket keys required to cover a specific time window.
37
- #
38
- # @param light_name [String] The name of the light (used as part of the Redis key).
39
- # @param metric [String] The metric type (e.g., "errors").
40
- # @param window_end [Time, Numeric] The end time of the window (can be a Time object or a numeric timestamp).
41
- # @param window_size [Numeric] The size of the time window in seconds.
42
- # @return [Array<String>] A list of Redis keys for the buckets that cover the time window.
43
- # @api private
44
- def buckets_for_window(light_name, metric:, window_end:, window_size:)
45
- window_end_ts = window_end.to_i
46
- window_start_ts = window_end_ts - [window_size, METRICS_RETENTION_TIME].compact.min.to_i
47
-
48
- # Find bucket timestamps that contain any part of the window
49
- start_bucket = (window_start_ts / bucket_size) * bucket_size
50
-
51
- # End bucket is the last bucket that contains data within our window
52
- end_bucket = ((window_end_ts - 1) / bucket_size) * bucket_size
53
-
54
- (start_bucket..end_bucket).step(bucket_size).map do |bucket_start|
55
- bucket_key(light_name, metric: metric, time: bucket_start)
56
- end
57
- end
58
-
59
- # Generates a Redis key for a specific metric and time.
60
- #
61
- # @param light_name [String] The name of the light.
62
- # @param metric [String] The metric type (e.g., "errors").
63
- # @param time [Time, Numeric] The time for which to generate the key.
64
- # @return [String] The generated Redis key.
65
- def bucket_key(light_name, metric:, time:)
66
- key("metrics", light_name, metric, (time.to_i / bucket_size) * bucket_size)
67
- end
68
-
69
- BUCKET_SIZE = 3600 # 1h
70
- private_constant :BUCKET_SIZE
71
-
72
- private def bucket_size
73
- BUCKET_SIZE
74
- end
75
- end
76
-
77
- KEY_SEPARATOR = ":"
78
- KEY_PREFIX = %w[stoplight v5].join(KEY_SEPARATOR)
79
-
80
- # @!attribute recovery_lock_store
81
- # @return [Stoplight::Infrastructure::Redis::DataStore::RecoveryLockStore]
82
- protected attr_reader :recovery_lock_store
83
-
84
- # @!attribute scripting
85
- # @return [Stoplight::Infrastructure::Redis::DataStore::Scripting]
86
- protected attr_reader :scripting
87
-
88
- # @!attribute redis
89
- # @return [::Redis | ConnectionPool<::Redis>]
90
- protected attr_reader :redis
91
-
92
- # @!attribute warn_on_clock_skew
93
- # @return [Boolean]
94
- protected attr_reader :warn_on_clock_skew
95
-
96
- # @!attribute clock
97
- # @return [Stoplight::Domain::_Clock]
98
- private attr_reader :clock
99
-
100
- # @param redis [::Redis, ConnectionPool<::Redis>]
101
- # @param recovery_lock_store [Stoplight::Infrastructure::Redis::DataStore::RecoveryLockStore]
102
- # @param warn_on_clock_skew [Boolean] (true) Whether to warn about clock skew between Redis and
103
- # @param scripting [Stoplight::Infrastructure::Redis::DataStore::Scripting]
104
- # @param clock [Stoplight::Domain::_Clock]
105
- # the application server
106
- def initialize(redis:, recovery_lock_store:, scripting:, clock:, warn_on_clock_skew: true)
107
- @clock = clock
108
- @warn_on_clock_skew = warn_on_clock_skew
109
- @redis = redis
110
- @recovery_lock_store = recovery_lock_store
111
- @scripting = scripting
112
- end
113
-
114
- def names
115
- metadata, recovery_metrics = @redis.then do |client|
116
- [
117
- [key("metadata", "*"), /^#{key("metadata", "")}/],
118
- [key("recovery_metrics", "*"), /^#{key("recovery_metrics", "")}/]
119
- ].map do |(pattern, prefix_regex)|
120
- client.scan_each(match: pattern).to_a.map do |key|
121
- key.sub(prefix_regex, "")
122
- end
123
- end
124
- end
125
- metadata + recovery_metrics
126
- end
127
-
128
- # @param config [Stoplight::Domain::Config]
129
- # @return [Stoplight::Domain::MetricsSnapshot]
130
- def get_metrics(config)
131
- config.name
132
-
133
- window_end_ts = clock.current_time.to_f
134
- window_start_ts = window_end_ts - config.window_size.to_i
135
-
136
- if config.window_size
137
- failure_keys = failure_bucket_keys(config, window_end: window_end_ts)
138
- success_keys = success_bucket_keys(config, window_end: window_end_ts)
139
- else
140
- failure_keys = []
141
- success_keys = []
142
- end
143
-
144
- successes, errors, last_success_at, last_error_json, consecutive_errors, consecutive_successes = scripting.call(
145
- :get_metrics,
146
- args: [
147
- failure_keys.count,
148
- window_start_ts,
149
- window_end_ts,
150
- "last_success_at", "last_error_json", "consecutive_errors", "consecutive_successes"
151
- ],
152
- keys: [
153
- metadata_key(config),
154
- *success_keys,
155
- *failure_keys
156
- ]
157
- )
158
- consecutive_errors = config.window_size ? [consecutive_errors.to_i, errors].min : consecutive_errors.to_i
159
- consecutive_successes = config.window_size ? [consecutive_successes.to_i, successes].min : consecutive_successes.to_i
160
-
161
- Domain::MetricsSnapshot.new(
162
- successes: (successes if config.window_size),
163
- errors: (errors if config.window_size),
164
- consecutive_errors:,
165
- consecutive_successes:,
166
- last_error: deserialize_failure(last_error_json),
167
- last_success_at: (clock.at(last_success_at.to_f) if last_success_at)
168
- )
169
- end
170
-
171
- # @param config [Stoplight::Domain::Config]
172
- # @return [Stoplight::Domain::MetricsSnapshot]
173
- def get_recovery_metrics(config)
174
- last_success_at, last_error_json, consecutive_errors, consecutive_successes = @redis.with do |client|
175
- client.hmget(
176
- recovery_metrics_key(config),
177
- "last_success_at", "last_error_json", "consecutive_errors", "consecutive_successes"
178
- )
179
- end
180
-
181
- Domain::MetricsSnapshot.new(
182
- successes: nil, errors: nil,
183
- consecutive_errors: consecutive_errors.to_i,
184
- consecutive_successes: consecutive_successes.to_i,
185
- last_error: deserialize_failure(last_error_json),
186
- last_success_at: (clock.at(last_success_at.to_f) if last_success_at)
187
- )
188
- end
189
-
190
- # @return [Stoplight::Domain::StateSnapshot]
191
- def get_state_snapshot(config)
192
- detect_clock_skew
193
-
194
- breached_at_raw, locked_state, recovery_scheduled_after_raw, recovery_started_at_raw = @redis.with do |client|
195
- client.hmget(metadata_key(config), :breached_at, :locked_state, :recovery_scheduled_after, :recovery_started_at)
196
- end
197
- breached_at = breached_at_raw&.to_f
198
- recovery_scheduled_after = recovery_scheduled_after_raw&.to_f
199
- recovery_started_at = recovery_started_at_raw&.to_f
200
-
201
- Domain::StateSnapshot.new(
202
- breached_at: (clock.at(breached_at) if breached_at),
203
- locked_state: locked_state || State::UNLOCKED,
204
- recovery_scheduled_after: (clock.at(recovery_scheduled_after) if recovery_scheduled_after),
205
- recovery_started_at: (clock.at(recovery_started_at) if recovery_started_at),
206
- time: clock.current_time
207
- )
208
- end
209
-
210
- def clear_metrics(config)
211
- if config.window_size
212
- window_end_ts = clock.current_time.to_i
213
- @redis.with do |client|
214
- client.multi do |tx|
215
- tx.unlink(
216
- *failure_bucket_keys(config, window_end: window_end_ts),
217
- *success_bucket_keys(config, window_end: window_end_ts)
218
- )
219
- tx.hdel(metadata_key(config), "last_success_at", "last_error_json", "consecutive_errors", "consecutive_successes")
220
- end
221
- end
222
- else
223
- @redis.with do |client|
224
- client.hdel(metadata_key(config), "last_success_at", "last_error_json", "consecutive_errors", "consecutive_successes")
225
- end
226
- end
227
- end
228
-
229
- def clear_recovery_metrics(config)
230
- @redis.with do |client|
231
- client.del(recovery_metrics_key(config))
232
- end
233
- end
234
-
235
- # @param config [Stoplight::Domain::Config] The light configuration.
236
- # @param exception [Exception]
237
- # @return [void]
238
- def record_failure(config, exception)
239
- current_time = clock.current_time
240
- current_ts = clock.current_time.to_f
241
- failure = Domain::Failure.from_error(exception, time: current_time)
242
-
243
- scripting.call(
244
- :record_failure,
245
- args: [current_ts, SecureRandom.hex(12), serialize_failure(failure), metrics_ttl(config), metadata_ttl],
246
- keys: [
247
- metadata_key(config),
248
- config.window_size && errors_key(config, time: current_ts)
249
- ].compact
250
- )
251
- end
252
-
253
- def record_success(config, request_id: SecureRandom.hex(12))
254
- current_ts = clock.current_time.to_f
255
-
256
- scripting.call(
257
- :record_success,
258
- args: [current_ts, request_id, metrics_ttl(config), metadata_ttl],
259
- keys: [
260
- metadata_key(config),
261
- config.window_size && successes_key(config, time: current_ts)
262
- ].compact
263
- )
264
- end
265
-
266
- # Records a failed recovery probe for a specific light configuration.
267
- #
268
- # @param config [Stoplight::Domain::Config] The light configuration.
269
- # @param exception [Exception]
270
- # @return [void]
271
- def record_recovery_probe_failure(config, exception)
272
- current_time = clock.current_time
273
- current_ts = clock.current_time.to_f
274
- failure = Domain::Failure.from_error(exception, time: current_time)
275
-
276
- scripting.call(
277
- :record_recovery_probe_failure,
278
- args: [current_ts, serialize_failure(failure)],
279
- keys: [recovery_metrics_key(config)]
280
- )
281
- end
282
-
283
- # Records a successful recovery probe for a specific light configuration.
284
- #
285
- # @param config [Stoplight::Domain::Config] The light configuration.
286
- # @return [void]
287
- def record_recovery_probe_success(config)
288
- current_ts = clock.current_time.to_f
289
-
290
- scripting.call(
291
- :record_recovery_probe_success,
292
- args: [current_ts],
293
- keys: [recovery_metrics_key(config)]
294
- )
295
- end
296
-
297
- def set_state(config, state)
298
- @redis.then do |client|
299
- client.hset(metadata_key(config), "locked_state", state)
300
- end
301
- state
302
- end
303
-
304
- def inspect
305
- "#<#{self.class.name} redis=#{@redis.inspect}>"
306
- end
307
-
308
- # Combined method that performs the state transition based on color
309
- #
310
- # @param config [Stoplight::Domain::Config] The light configuration
311
- # @param color [String] The color to transition to ("green", "yellow", or "red")
312
- # @return [Boolean] true if this is the first instance to detect this transition
313
- def transition_to_color(config, color)
314
- case color
315
- when Color::GREEN
316
- transition_to_green(config)
317
- when Color::YELLOW
318
- transition_to_yellow(config)
319
- when Color::RED
320
- transition_to_red(config)
321
- else
322
- raise ArgumentError, "Invalid color: #{color}"
323
- end
324
- end
325
-
326
- # @param config [Stoplight::Domain::Config]
327
- # @return [Stoplight::Infrastructure::Redis::DataStore::RecoveryLockToken, nil]
328
- def acquire_recovery_lock(config)
329
- recovery_lock_store.acquire_lock(config.name)
330
- end
331
-
332
- # @param lock [Stoplight::Infrastructure::Redis::DataStore::RecoveryLockToken]
333
- # @return [void]
334
- def release_recovery_lock(lock)
335
- recovery_lock_store.release_lock(lock)
336
- end
337
-
338
- # Transitions to GREEN state and ensures only one notification
339
- #
340
- # @param config [Stoplight::Domain::Config] The light configuration
341
- # @return [Boolean] true if this is the first instance to detect this transition
342
- private def transition_to_green(config)
343
- current_ts = clock.current_time.to_f
344
- meta_key = metadata_key(config)
345
-
346
- became_green = scripting.call(
347
- :transition_to_green,
348
- args: [current_ts],
349
- keys: [meta_key]
350
- )
351
- became_green == 1
352
- end
353
-
354
- # Transitions to YELLOW (recovery) state and ensures only one notification
355
- #
356
- # @param config [Stoplight::Domain::Config] The light configuration
357
- # @return [Boolean] true if this is the first instance to detect this transition
358
- private def transition_to_yellow(config)
359
- current_ts = clock.current_time.to_f
360
- meta_key = metadata_key(config)
361
-
362
- became_yellow = scripting.call(
363
- :transition_to_yellow,
364
- args: [current_ts],
365
- keys: [meta_key]
366
- )
367
- became_yellow == 1
368
- end
369
-
370
- # Transitions to RED state and ensures only one notification
371
- #
372
- # @param config [Stoplight::Domain::Config] The light configuration
373
- # @return [Boolean] true if this is the first instance to detect this transition
374
- private def transition_to_red(config)
375
- current_ts = clock.current_time.to_f
376
- meta_key = metadata_key(config)
377
- recovery_scheduled_after_ts = current_ts + config.cool_off_time
378
-
379
- became_red = scripting.call(
380
- :transition_to_red,
381
- args: [current_ts, recovery_scheduled_after_ts],
382
- keys: [meta_key]
383
- )
384
-
385
- became_red == 1
386
- end
387
-
388
- # Removes all traces of a light from Redis metadata (metrics will expire by TTL).
389
- #
390
- # @param config [Stoplight::Domain::Config] The light configuration.
391
- # @return [void]
392
- def delete_light(config)
393
- @redis.then do |client|
394
- client.del(metadata_key(config), recovery_metrics_key(config))
395
- end
396
- end
397
-
398
- # @param failure_json [String, nil]
399
- # @return [Domain::Failure, nil]
400
- private def deserialize_failure(failure_json)
401
- return if failure_json.nil?
402
-
403
- object = JSON.parse(failure_json)
404
- error_object = object["error"]
405
-
406
- error_class = error_object["class"]
407
- error_message = error_object["message"]
408
- time = clock.at(object["time"])
409
-
410
- Domain::Failure.new(error_class, error_message, time)
411
- end
412
-
413
- # @param failure [Domain::Failure]
414
- # @return [String]
415
- private def serialize_failure(failure)
416
- JSON.generate(
417
- {
418
- error: {
419
- class: failure.error_class,
420
- message: failure.error_message
421
- },
422
- time: failure.time.to_f
423
- }
424
- )
425
- end
426
-
427
- def_delegator "self.class", :key
428
-
429
- private def failure_bucket_keys(config, window_end:)
430
- self.class.buckets_for_window(
431
- config.name,
432
- metric: "failure",
433
- window_end: window_end,
434
- window_size: config.window_size
435
- )
436
- end
437
-
438
- private def success_bucket_keys(config, window_end:)
439
- self.class.buckets_for_window(
440
- config.name,
441
- metric: "success",
442
- window_end: window_end,
443
- window_size: config.window_size
444
- )
445
- end
446
-
447
- private def recovery_probe_failure_bucket_keys(config, window_end:)
448
- self.class.buckets_for_window(
449
- config.name,
450
- metric: "recovery_probe_failure",
451
- window_end: window_end,
452
- window_size: config.cool_off_time
453
- )
454
- end
455
-
456
- private def recovery_probe_success_bucket_keys(config, window_end:)
457
- self.class.buckets_for_window(
458
- config.name,
459
- metric: "recovery_probe_success",
460
- window_end: window_end,
461
- window_size: config.cool_off_time
462
- )
463
- end
464
-
465
- private def successes_key(config, time:)
466
- self.class.bucket_key(config.name, metric: "success", time:)
467
- end
468
-
469
- private def errors_key(config, time:)
470
- self.class.bucket_key(config.name, metric: "failure", time:)
471
- end
472
-
473
- private def recovery_metrics_key(config)
474
- key("recovery_metrics", config.name)
475
- end
476
-
477
- private def metadata_key(config)
478
- key("metadata", config.name)
479
- end
480
-
481
- METRICS_TTL = 86400 # 1 day
482
- private_constant :METRICS_TTL
483
-
484
- private def metrics_ttl(config)
485
- config.window_size || METRICS_TTL
486
- end
487
-
488
- METADATA_TTL = 86400 * 7 # 7 days
489
- private_constant :METADATA_TTL
490
-
491
- private def metadata_ttl
492
- METADATA_TTL
493
- end
494
-
495
- SKEW_TOLERANCE = 5 # seconds
496
- private_constant :SKEW_TOLERANCE
497
-
498
- private def detect_clock_skew
499
- return unless @warn_on_clock_skew
500
- return unless should_sample?(0.01) # 1% chance
501
-
502
- redis_seconds, _redis_millis = @redis.then(&:time)
503
- app_seconds = clock.current_time.to_i
504
- if (redis_seconds - app_seconds).abs > SKEW_TOLERANCE
505
- warn("Detected clock skew between Redis and the application server. Redis time: #{redis_seconds}, Application time: #{app_seconds}. See https://github.com/bolshakov/stoplight/wiki/Clock-Skew-and-Stoplight-Reliability")
506
- end
507
- end
508
-
509
- private def should_sample?(probability)
510
- rand <= probability
511
- end
512
- end
513
- # steep:ignore:end
514
- end
515
- end
516
- end