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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -1
- data/LICENSE.md +1 -0
- data/README.md +132 -79
- data/UPGRADING.md +265 -6
- data/lib/stoplight/admin/actions/action.rb +4 -12
- data/lib/stoplight/admin/actions/lock.rb +12 -9
- data/lib/stoplight/admin/actions/lock_all.rb +27 -0
- data/lib/stoplight/admin/actions/remove.rb +12 -9
- data/lib/stoplight/admin/actions/stats.rb +15 -12
- data/lib/stoplight/admin/actions/unlock.rb +10 -9
- data/lib/stoplight/admin/assets/apple-touch-icon.png +0 -0
- data/lib/stoplight/admin/assets/favicon.ico +0 -0
- data/lib/stoplight/admin/assets/flowbite.min.css +2 -0
- data/lib/stoplight/admin/assets/flowbite.min.js +1 -0
- data/lib/stoplight/admin/assets/icon.svg +7 -0
- data/lib/stoplight/admin/assets/turbo.es2017-esm.min.js +34 -0
- data/lib/stoplight/admin/config_registry.rb +40 -0
- data/lib/stoplight/admin/dependencies.rb +29 -28
- data/lib/stoplight/admin/helpers.rb +50 -17
- data/lib/stoplight/admin/light_view.rb +184 -0
- data/lib/stoplight/admin/lights_stats.rb +7 -9
- data/lib/stoplight/admin/views/_card.erb +19 -21
- data/lib/stoplight/admin/views/index.erb +9 -3
- data/lib/stoplight/admin/views/layout.erb +45 -13
- data/lib/stoplight/admin.rb +110 -21
- data/lib/stoplight/data_store.rb +18 -8
- data/lib/stoplight/domain/config.rb +4 -1
- data/lib/stoplight/domain/error_tracking_policy.rb +9 -0
- data/lib/stoplight/domain/failure.rb +4 -0
- data/lib/stoplight/domain/id.rb +13 -0
- data/lib/stoplight/domain/light.rb +35 -77
- data/lib/stoplight/domain/lock_control.rb +55 -0
- data/lib/stoplight/domain/matcher_validator.rb +24 -0
- data/lib/stoplight/domain/state_snapshot.rb +2 -6
- data/lib/stoplight/domain/strategies/green_run_strategy.rb +33 -19
- data/lib/stoplight/domain/strategies/red_run_strategy.rb +8 -2
- data/lib/stoplight/domain/strategies/yellow_run_strategy.rb +56 -32
- data/lib/stoplight/domain/telemetry/bus.rb +90 -0
- data/lib/stoplight/domain/telemetry/consumer.rb +18 -0
- data/lib/stoplight/domain/telemetry/emitter.rb +45 -0
- data/lib/stoplight/domain/telemetry/envelope.rb +15 -0
- data/lib/stoplight/domain/telemetry/failure.rb +13 -0
- data/lib/stoplight/domain/telemetry/light_registered.rb +12 -0
- data/lib/stoplight/domain/telemetry/lock_changed.rb +19 -0
- data/lib/stoplight/domain/telemetry/metrics.rb +15 -0
- data/lib/stoplight/domain/telemetry/recovery_failed.rb +20 -0
- data/lib/stoplight/domain/telemetry/recovery_probe_completed.rb +15 -0
- data/lib/stoplight/domain/telemetry/recovery_started.rb +18 -0
- data/lib/stoplight/domain/telemetry/recovery_succeeded.rb +19 -0
- data/lib/stoplight/domain/telemetry/run_completed.rb +17 -0
- data/lib/stoplight/domain/telemetry/run_recorder.rb +58 -0
- data/lib/stoplight/domain/telemetry/settings.rb +21 -0
- data/lib/stoplight/domain/telemetry/state_transitioned.rb +11 -0
- data/lib/stoplight/domain/telemetry/subscription.rb +11 -0
- data/lib/stoplight/domain/telemetry/traffic_breached.rb +20 -0
- data/lib/stoplight/domain/tracker/recovery_probe.rb +61 -17
- data/lib/stoplight/domain/tracker/request.rb +17 -8
- data/lib/stoplight/domain/traffic_control/consecutive_errors.rb +13 -3
- data/lib/stoplight/domain/traffic_control/error_rate.rb +16 -12
- data/lib/stoplight/domain/traffic_recovery/consecutive_successes.rb +9 -3
- data/lib/stoplight/error.rb +10 -1
- data/lib/stoplight/infrastructure/config_serializer.rb +50 -0
- data/lib/stoplight/infrastructure/fail_safe/error_notifier.rb +25 -0
- data/lib/stoplight/infrastructure/fail_safe/storage/registry.rb +68 -0
- data/lib/stoplight/infrastructure/memory/storage/registry.rb +18 -0
- data/lib/stoplight/infrastructure/memory/storage/unbounded_metrics.rb +29 -32
- data/lib/stoplight/infrastructure/memory/storage/window_metrics/sliding_window.rb +74 -0
- data/lib/stoplight/infrastructure/memory/storage/window_metrics.rb +25 -24
- data/lib/stoplight/infrastructure/notifier/fail_safe.rb +3 -8
- data/lib/stoplight/infrastructure/notifier/generic.rb +3 -3
- data/lib/stoplight/infrastructure/redis/key.rb +25 -0
- data/lib/stoplight/infrastructure/redis/storage/now.lua +9 -0
- data/lib/stoplight/infrastructure/redis/storage/recovery_lock.rb +2 -4
- data/lib/stoplight/infrastructure/redis/storage/recovery_metrics.rb +1 -1
- data/lib/stoplight/infrastructure/redis/storage/registry.rb +73 -0
- data/lib/stoplight/infrastructure/redis/storage/scripting.rb +54 -3
- data/lib/stoplight/infrastructure/redis/storage/state/transition_to_green.lua +3 -1
- data/lib/stoplight/infrastructure/redis/storage/state/transition_to_red.lua +4 -2
- data/lib/stoplight/infrastructure/redis/storage/state/transition_to_yellow.lua +3 -1
- data/lib/stoplight/infrastructure/redis/storage/state.rb +8 -8
- data/lib/stoplight/infrastructure/redis/storage/unbounded_metrics/record_failure.lua +20 -21
- data/lib/stoplight/infrastructure/redis/storage/unbounded_metrics/record_success.lua +11 -19
- data/lib/stoplight/infrastructure/redis/storage/unbounded_metrics.rb +20 -16
- data/lib/stoplight/infrastructure/redis/storage/window_metrics/_evict.lua +44 -0
- data/lib/stoplight/infrastructure/redis/storage/window_metrics/metrics_snapshot.lua +14 -21
- data/lib/stoplight/infrastructure/redis/storage/window_metrics/record_failure.lua +38 -36
- data/lib/stoplight/infrastructure/redis/storage/window_metrics/record_success.lua +23 -30
- data/lib/stoplight/infrastructure/redis/storage/window_metrics.rb +45 -135
- data/lib/stoplight/infrastructure/system_clock.rb +4 -0
- data/lib/stoplight/telemetry.rb +19 -0
- data/lib/stoplight/types.rb +15 -2
- data/lib/stoplight/version.rb +1 -1
- data/lib/stoplight/wiring/config_compatibility_validator.rb +25 -2
- data/lib/stoplight/wiring/default.rb +1 -1
- data/lib/stoplight/wiring/default_config.rb +2 -1
- data/lib/stoplight/wiring/default_configuration.rb +3 -2
- data/lib/stoplight/wiring/external_caller.rb +27 -0
- data/lib/stoplight/wiring/fail_safe_config.rb +11 -0
- data/lib/stoplight/wiring/global_state.rb +93 -0
- data/lib/stoplight/wiring/{light_factory → light_configuration_dsl}/traffic_control_dsl.rb +3 -5
- data/lib/stoplight/wiring/{light_factory → light_configuration_dsl}/traffic_recovery_dsl.rb +2 -2
- data/lib/stoplight/wiring/light_configuration_dsl.rb +97 -0
- data/lib/stoplight/wiring/light_factory.rb +154 -97
- data/lib/stoplight/wiring/notifier_bridge.rb +33 -0
- data/lib/stoplight/wiring/redis/backend.rb +1 -1
- data/lib/stoplight/wiring/system/storage.rb +69 -0
- data/lib/stoplight/wiring/system.rb +125 -56
- data/lib/stoplight/wiring/{configuration_dsl.rb → system_configuration_dsl.rb} +13 -43
- data/lib/stoplight.rb +50 -194
- data/sig/sinatra/base.rbs +6 -0
- data/sig/stdlib/securerandom.rbs +4 -0
- data/sig/stoplight/admin/actions/action.rbs +10 -0
- data/sig/stoplight/admin/actions/lock.rbs +17 -0
- data/sig/stoplight/admin/actions/lock_all.rbs +17 -0
- data/sig/stoplight/admin/actions/remove.rbs +22 -0
- data/sig/stoplight/admin/actions/stats.rbs +28 -0
- data/sig/stoplight/admin/actions/unlock.rbs +17 -0
- data/sig/stoplight/admin/config_registry.rbs +20 -0
- data/sig/stoplight/admin/dependencies.rbs +16 -0
- data/sig/stoplight/admin/helpers.rbs +17 -0
- data/sig/stoplight/admin/light_view.rbs +39 -0
- data/sig/stoplight/admin/lights_stats.rbs +30 -0
- data/sig/stoplight/admin.rbs +14 -0
- data/sig/stoplight/color.rbs +3 -3
- data/sig/{_private/stoplight/data_store.rbs → stoplight/data_store/base.rbs} +1 -0
- data/sig/stoplight/data_store/memory.rbs +9 -0
- data/sig/stoplight/data_store/redis.rbs +17 -0
- data/sig/{_private/stoplight → stoplight}/domain/config.rbs +28 -24
- data/sig/{_private/stoplight → stoplight}/domain/error_tracking_policy.rbs +4 -0
- data/sig/{_private/stoplight → stoplight}/domain/failure.rbs +2 -0
- data/sig/stoplight/domain/id.rbs +7 -0
- data/sig/stoplight/domain/light.rbs +39 -0
- data/sig/{_private/stoplight → stoplight}/domain/light_info.rbs +1 -5
- data/sig/stoplight/domain/lock_control.rbs +16 -0
- data/sig/stoplight/domain/matcher_validator.rbs +11 -0
- data/sig/{_private/stoplight → stoplight}/domain/ports/clock.rbs +6 -0
- data/sig/stoplight/domain/ports/data_store.rbs +9 -0
- data/sig/stoplight/domain/ports/error_notifier.rbs +12 -0
- data/sig/stoplight/domain/ports/exception_matcher.rbs +10 -0
- data/sig/{_private/stoplight → stoplight}/domain/ports/metrics_store.rbs +2 -2
- data/sig/stoplight/domain/ports/registry.rbs +13 -0
- data/sig/{_private/stoplight → stoplight}/domain/ports/run_strategy.rbs +2 -1
- data/sig/stoplight/domain/ports/state_transition_notifier.rbs +18 -0
- data/sig/stoplight/domain/ports/telemetry.rbs +28 -0
- data/sig/stoplight/domain/ports/telemetry_publisher.rbs +14 -0
- data/sig/{_private/stoplight → stoplight}/domain/ports/traffic_control.rbs +7 -0
- data/sig/{_private/stoplight → stoplight}/domain/ports/traffic_recovery.rbs +2 -3
- data/sig/stoplight/domain/strategies/green_run_strategy.rbs +22 -0
- data/sig/stoplight/domain/strategies/red_run_strategy.rbs +19 -0
- data/sig/{_private/stoplight → stoplight}/domain/strategies/yellow_run_strategy.rbs +23 -12
- data/sig/stoplight/domain/telemetry/bus.rbs +49 -0
- data/sig/stoplight/domain/telemetry/consumer.rbs +13 -0
- data/sig/stoplight/domain/telemetry/emitter.rbs +51 -0
- data/sig/stoplight/domain/telemetry/envelope.rbs +30 -0
- data/sig/stoplight/domain/telemetry/failure.rbs +23 -0
- data/sig/stoplight/domain/telemetry/light_registered.rbs +23 -0
- data/sig/stoplight/domain/telemetry/lock_changed.rbs +31 -0
- data/sig/stoplight/domain/telemetry/metrics.rbs +27 -0
- data/sig/stoplight/domain/telemetry/recovery_failed.rbs +36 -0
- data/sig/stoplight/domain/telemetry/recovery_probe_completed.rbs +29 -0
- data/sig/stoplight/domain/telemetry/recovery_started.rbs +26 -0
- data/sig/stoplight/domain/telemetry/recovery_succeeded.rbs +31 -0
- data/sig/stoplight/domain/telemetry/run_completed.rbs +38 -0
- data/sig/stoplight/domain/telemetry/run_recorder.rbs +27 -0
- data/sig/stoplight/domain/telemetry/settings.rbs +47 -0
- data/sig/stoplight/domain/telemetry/state_transitioned.rbs +11 -0
- data/sig/stoplight/domain/telemetry/subscription.rbs +9 -0
- data/sig/stoplight/domain/telemetry/traffic_breached.rbs +36 -0
- data/sig/stoplight/domain/telemetry/types.rbs +32 -0
- data/sig/{_private/stoplight → stoplight}/domain/tracker/recovery_probe.rbs +10 -6
- data/sig/{_private/stoplight → stoplight}/domain/tracker/request.rbs +3 -3
- data/sig/{_private/stoplight → stoplight}/domain/traffic_control/consecutive_errors.rbs +2 -0
- data/sig/{_private/stoplight → stoplight}/domain/traffic_control/error_rate.rbs +3 -2
- data/sig/{_private/stoplight → stoplight}/domain/traffic_recovery/consecutive_successes.rbs +2 -0
- data/sig/stoplight/domain/types.rbs +25 -0
- data/sig/stoplight/error.rbs +8 -0
- data/sig/stoplight/generators/rails_generators_base.rbs +11 -0
- data/sig/stoplight/infrastructure/config_serializer.rbs +12 -0
- data/sig/stoplight/infrastructure/fail_safe/error_notifier.rbs +13 -0
- data/sig/{_private/stoplight → stoplight}/infrastructure/fail_safe/storage/metrics.rbs +2 -2
- data/sig/{_private/stoplight → stoplight}/infrastructure/fail_safe/storage/recovery_lock.rbs +2 -2
- data/sig/stoplight/infrastructure/fail_safe/storage/registry.rbs +23 -0
- data/sig/{_private/stoplight → stoplight}/infrastructure/fail_safe/storage/state.rbs +4 -4
- data/sig/stoplight/infrastructure/memory/storage/registry.rbs +13 -0
- data/sig/{_private/stoplight → stoplight}/infrastructure/memory/storage/state.rbs +3 -3
- data/sig/{_private/stoplight → stoplight}/infrastructure/memory/storage/unbounded_metrics.rbs +7 -7
- data/sig/stoplight/infrastructure/memory/storage/window_metrics/sliding_window.rbs +27 -0
- data/sig/{_private/stoplight → stoplight}/infrastructure/memory/storage/window_metrics.rbs +7 -7
- data/sig/stoplight/infrastructure/notifier/fail_safe.rbs +15 -0
- data/sig/{_private/stoplight → stoplight}/infrastructure/notifier/generic.rbs +1 -1
- data/sig/{_private/stoplight → stoplight}/infrastructure/notifier/io.rbs +1 -1
- data/sig/{_private/stoplight → stoplight}/infrastructure/notifier/logger.rbs +1 -1
- data/sig/stoplight/infrastructure/redis/key.rbs +10 -0
- data/sig/{_private/stoplight → stoplight}/infrastructure/redis/storage/recovery_lock.rbs +2 -2
- data/sig/stoplight/infrastructure/redis/storage/registry.rbs +27 -0
- data/sig/stoplight/infrastructure/redis/storage/scripting.rbs +34 -0
- data/sig/{_private/stoplight → stoplight}/infrastructure/redis/storage/state.rbs +4 -4
- data/sig/{_private/stoplight → stoplight}/infrastructure/redis/storage/unbounded_metrics.rbs +8 -1
- data/sig/stoplight/infrastructure/redis/storage/window_metrics.rbs +35 -0
- data/sig/stoplight/infrastructure/types.rbs +6 -0
- data/sig/stoplight/notifier.rbs +1 -1
- data/sig/stoplight/ports/system.rbs +16 -10
- data/sig/stoplight/state.rbs +3 -3
- data/sig/stoplight/telemetry.rbs +17 -0
- data/sig/stoplight/types.rbs +9 -0
- data/sig/{_private/stoplight → stoplight}/wiring/config_compatibility_validator.rbs +2 -0
- data/sig/stoplight/wiring/default.rbs +26 -0
- data/sig/stoplight/wiring/default_configuration.rbs +39 -0
- data/sig/stoplight/wiring/external_caller.rbs +13 -0
- data/sig/stoplight/wiring/fail_safe_config.rbs +7 -0
- data/sig/stoplight/wiring/global_state.rbs +36 -0
- data/sig/{_private/stoplight/wiring/light_factory → stoplight/wiring/light_configuration_dsl}/traffic_control_dsl.rbs +1 -1
- data/sig/{_private/stoplight/wiring/light_factory → stoplight/wiring/light_configuration_dsl}/traffic_recovery_dsl.rbs +1 -1
- data/sig/stoplight/wiring/light_configuration_dsl.rbs +38 -0
- data/sig/stoplight/wiring/light_factory.rbs +78 -0
- data/sig/stoplight/wiring/notifier_bridge.rbs +15 -0
- data/sig/stoplight/wiring/notifier_factory.rbs +10 -0
- data/sig/{_private/stoplight → stoplight}/wiring/redis/backend.rbs +6 -6
- data/sig/stoplight/wiring/system/storage.rbs +35 -0
- data/sig/stoplight/wiring/system.rbs +30 -0
- data/sig/stoplight/wiring/system_configuration_dsl.rbs +39 -0
- data/sig/stoplight/wiring/types.rbs +6 -0
- data/sig/stoplight.rbs +37 -54
- metadata +190 -143
- data/lib/stoplight/admin/actions/lock_all_green.rb +0 -18
- data/lib/stoplight/admin/actions/lock_green.rb +0 -23
- data/lib/stoplight/admin/actions/lock_red.rb +0 -23
- data/lib/stoplight/admin/lights_repository/light.rb +0 -171
- data/lib/stoplight/admin/lights_repository.rb +0 -87
- data/lib/stoplight/domain/light/configuration_builder_interface.rb +0 -236
- data/lib/stoplight/infrastructure/fail_safe/data_store.rb +0 -152
- data/lib/stoplight/infrastructure/memory/data_store/metrics.rb +0 -27
- data/lib/stoplight/infrastructure/memory/data_store/recovery_lock_store.rb +0 -52
- data/lib/stoplight/infrastructure/memory/data_store/recovery_lock_token.rb +0 -17
- data/lib/stoplight/infrastructure/memory/data_store/sliding_window.rb +0 -74
- data/lib/stoplight/infrastructure/memory/data_store/state.rb +0 -21
- data/lib/stoplight/infrastructure/memory/data_store.rb +0 -342
- data/lib/stoplight/infrastructure/redis/data_store/lua_scripts/get_metrics.lua +0 -26
- data/lib/stoplight/infrastructure/redis/data_store/lua_scripts/record_failure.lua +0 -36
- data/lib/stoplight/infrastructure/redis/data_store/lua_scripts/record_recovery_probe_failure.lua +0 -27
- data/lib/stoplight/infrastructure/redis/data_store/lua_scripts/record_recovery_probe_success.lua +0 -23
- data/lib/stoplight/infrastructure/redis/data_store/lua_scripts/record_success.lua +0 -35
- data/lib/stoplight/infrastructure/redis/data_store/lua_scripts/release_lock.lua +0 -6
- data/lib/stoplight/infrastructure/redis/data_store/lua_scripts/transition_to_green.lua +0 -10
- data/lib/stoplight/infrastructure/redis/data_store/lua_scripts/transition_to_red.lua +0 -10
- data/lib/stoplight/infrastructure/redis/data_store/lua_scripts/transition_to_yellow.lua +0 -9
- data/lib/stoplight/infrastructure/redis/data_store/recovery_lock_store.rb +0 -60
- data/lib/stoplight/infrastructure/redis/data_store/recovery_lock_token.rb +0 -28
- data/lib/stoplight/infrastructure/redis/data_store/scripting.rb +0 -73
- data/lib/stoplight/infrastructure/redis/data_store.rb +0 -516
- data/lib/stoplight/infrastructure/redis/storage/key_space.rb +0 -51
- data/lib/stoplight/infrastructure/storage/compatibility_metrics.rb +0 -41
- data/lib/stoplight/infrastructure/storage/compatibility_recovery_lock.rb +0 -33
- data/lib/stoplight/infrastructure/storage/compatibility_recovery_metrics.rb +0 -47
- data/lib/stoplight/infrastructure/storage/compatibility_state.rb +0 -44
- data/lib/stoplight/wiring/light_builder.rb +0 -198
- data/lib/stoplight/wiring/notifier_factory.rb +0 -26
- data/lib/stoplight/wiring/system/light_builder.rb +0 -47
- data/lib/stoplight/wiring/system/light_factory.rb +0 -64
- data/sig/_private/stoplight/domain/light.rbs +0 -25
- data/sig/_private/stoplight/domain/ports/data_store.rbs +0 -76
- data/sig/_private/stoplight/domain/ports/light_factory.rbs +0 -80
- data/sig/_private/stoplight/domain/strategies/green_run_strategy.rbs +0 -17
- data/sig/_private/stoplight/domain/strategies/red_run_strategy.rbs +0 -17
- data/sig/_private/stoplight/domain/tracker/base.rbs +0 -8
- data/sig/_private/stoplight/infrastructure/fail_safe/data_store.rbs +0 -26
- data/sig/_private/stoplight/infrastructure/memory/data_store/metrics.rbs +0 -25
- data/sig/_private/stoplight/infrastructure/memory/data_store/recovery_lock_store.rbs +0 -19
- data/sig/_private/stoplight/infrastructure/memory/data_store/recovery_lock_token.rbs +0 -17
- data/sig/_private/stoplight/infrastructure/memory/data_store/sliding_window.rbs +0 -27
- data/sig/_private/stoplight/infrastructure/memory/data_store/state.rbs +0 -17
- data/sig/_private/stoplight/infrastructure/memory/data_store.rbs +0 -30
- data/sig/_private/stoplight/infrastructure/notifier/fail_safe.rbs +0 -17
- data/sig/_private/stoplight/infrastructure/redis/data_store/recovery_lock_store.rbs +0 -24
- data/sig/_private/stoplight/infrastructure/redis/data_store/recovery_lock_token.rbs +0 -21
- data/sig/_private/stoplight/infrastructure/redis/data_store/scripting.rbs +0 -34
- data/sig/_private/stoplight/infrastructure/redis/data_store.rbs +0 -67
- data/sig/_private/stoplight/infrastructure/redis/storage/key_space.rbs +0 -19
- data/sig/_private/stoplight/infrastructure/redis/storage/scripting.rbs +0 -13
- data/sig/_private/stoplight/infrastructure/redis/storage/window_metrics.rbs +0 -34
- data/sig/_private/stoplight/infrastructure/storage/compatibility_metrics.rbs +0 -17
- data/sig/_private/stoplight/infrastructure/storage/compatibility_recovery_lock.rbs +0 -13
- data/sig/_private/stoplight/infrastructure/storage/compatibility_recovery_metrics.rbs +0 -14
- data/sig/_private/stoplight/infrastructure/storage/compatibility_state.rbs +0 -14
- data/sig/_private/stoplight/system/light_builder.rbs +0 -23
- data/sig/_private/stoplight/system/light_factory.rbs +0 -17
- data/sig/_private/stoplight/types.rbs +0 -6
- data/sig/_private/stoplight/wiring/configuration_dsl.rbs +0 -43
- data/sig/_private/stoplight/wiring/default.rbs +0 -26
- data/sig/_private/stoplight/wiring/default_configuration.rbs +0 -29
- data/sig/_private/stoplight/wiring/light_builder.rbs +0 -48
- data/sig/_private/stoplight/wiring/light_factory.rbs +0 -16
- data/sig/_private/stoplight/wiring/notifier_factory.rbs +0 -10
- data/sig/_private/stoplight/wiring/system.rbs +0 -15
- data/sig/_private/stoplight.rbs +0 -48
- data/sig/stoplight/data_store.rbs +0 -19
- data/sig/stoplight/ports/configuration.rbs +0 -19
- data/sig/stoplight/ports/exception_matcher.rbs +0 -8
- data/sig/stoplight/ports/light.rbs +0 -12
- data/sig/stoplight/ports/light_info.rbs +0 -5
- data/sig/stoplight/ports/state_transition_notifier.rbs +0 -15
- /data/sig/{_private/stoplight → stoplight}/common/deprecations.rbs +0 -0
- /data/sig/{_private/stoplight → stoplight}/domain/compatibility_result.rbs +0 -0
- /data/sig/{_private/stoplight → stoplight}/domain/metrics_snapshot.rbs +0 -0
- /data/sig/{_private/stoplight → stoplight}/domain/ports/recovery_lock_store.rbs +0 -0
- /data/sig/{_private/stoplight → stoplight}/domain/ports/recovery_lock_token.rbs +0 -0
- /data/sig/{_private/stoplight → stoplight}/domain/ports/state_store.rbs +0 -0
- /data/sig/{_private/stoplight → stoplight}/domain/state_snapshot.rbs +0 -0
- /data/sig/{_private/stoplight → stoplight}/domain/storage/recovery_lock_token.rbs +0 -0
- /data/sig/{_private/stoplight → stoplight}/domain/traffic_recovery.rbs +0 -0
- /data/sig/{_private → stoplight}/generators/stoplight/install/install_generator.rbs +0 -0
- /data/sig/{_private/stoplight → stoplight}/infrastructure/fail_safe/storage/recovery_lock_token.rbs +0 -0
- /data/sig/{_private/stoplight → stoplight}/infrastructure/memory/storage/recovery_lock.rbs +0 -0
- /data/sig/{_private/stoplight → stoplight}/infrastructure/memory/storage/recovery_metrics.rbs +0 -0
- /data/sig/{_private/stoplight → stoplight}/infrastructure/redis/storage/metrics.rbs +0 -0
- /data/sig/{_private/stoplight → stoplight}/infrastructure/redis/storage/recovery_metrics.rbs +0 -0
- /data/sig/{_private/stoplight → stoplight}/infrastructure/system_clock.rbs +0 -0
- /data/sig/{_private/stoplight → stoplight}/wiring/data_store_backend.rbs +0 -0
- /data/sig/{_private/stoplight → stoplight}/wiring/default_config.rbs +0 -0
- /data/sig/{_private/stoplight → stoplight}/wiring/memory/backend.rbs +0 -0
- /data/sig/{_private/stoplight → stoplight}/wiring/storage_set.rbs +0 -0
- /data/sig/{_private/stoplight → stoplight}/wiring/storage_set_builder.rbs +0 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stoplight
|
|
4
|
+
module Infrastructure
|
|
5
|
+
module Redis
|
|
6
|
+
module Storage
|
|
7
|
+
class Registry
|
|
8
|
+
def initialize(redis:, key_space:, clock:, config_serializer:)
|
|
9
|
+
@redis = redis
|
|
10
|
+
@key_space = key_space
|
|
11
|
+
@clock = clock
|
|
12
|
+
@config_serializer = config_serializer
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def ids
|
|
16
|
+
@redis.with do |conn|
|
|
17
|
+
conn.hkeys(key)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def register(config)
|
|
22
|
+
@redis.with do |conn|
|
|
23
|
+
conn.hset(
|
|
24
|
+
key,
|
|
25
|
+
config.id,
|
|
26
|
+
{
|
|
27
|
+
meta: {
|
|
28
|
+
version: 1,
|
|
29
|
+
registered_at: @clock.current_time.to_i
|
|
30
|
+
},
|
|
31
|
+
config: @config_serializer.call(config)
|
|
32
|
+
}.to_json
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def unregister(id)
|
|
38
|
+
@redis.with do |conn|
|
|
39
|
+
conn.hdel(key, id)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def all_configs
|
|
44
|
+
raw_lights_info = @redis.with do |conn|
|
|
45
|
+
conn.hgetall(key)
|
|
46
|
+
end
|
|
47
|
+
return [] unless raw_lights_info
|
|
48
|
+
raw_lights_info.filter_map do |_, config|
|
|
49
|
+
next unless config
|
|
50
|
+
|
|
51
|
+
begin
|
|
52
|
+
JSON.parse(config)["config"]
|
|
53
|
+
rescue JSON::ParserError
|
|
54
|
+
nil
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def config_for(id)
|
|
60
|
+
raw_light_info = @redis.with do |conn|
|
|
61
|
+
conn.hget(key, id)
|
|
62
|
+
end
|
|
63
|
+
return unless raw_light_info
|
|
64
|
+
light_info = JSON.parse(raw_light_info)
|
|
65
|
+
light_info["config"]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private def key = @key_space.join("lights")
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -4,12 +4,63 @@ module Stoplight
|
|
|
4
4
|
module Infrastructure
|
|
5
5
|
module Redis
|
|
6
6
|
module Storage
|
|
7
|
-
class Scripting
|
|
8
|
-
SCRIPTS_ROOT = __dir__
|
|
7
|
+
class Scripting
|
|
8
|
+
SCRIPTS_ROOT = T.must(__dir__)
|
|
9
9
|
private_constant :SCRIPTS_ROOT
|
|
10
10
|
|
|
11
|
+
INCLUDE_DIRECTIVE = /^--\s*@include\s+([\w\-\/]+)$/
|
|
12
|
+
private_constant :INCLUDE_DIRECTIVE
|
|
13
|
+
|
|
11
14
|
class << self
|
|
12
|
-
def
|
|
15
|
+
def default_scripts_path = [SCRIPTS_ROOT]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def initialize(redis:, scripts_path: self.class.default_scripts_path)
|
|
19
|
+
@scripts_path = scripts_path
|
|
20
|
+
@redis = redis
|
|
21
|
+
@shas = Hash.new do |hash, script_name|
|
|
22
|
+
hash[script_name] = Digest::SHA1.hexdigest(resolve_source(script_name))
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def call(script_name, keys: [], args: [])
|
|
27
|
+
retried = false
|
|
28
|
+
|
|
29
|
+
begin
|
|
30
|
+
@redis.then do |client|
|
|
31
|
+
client.evalsha(@shas[script_name], keys: keys.map(&:to_s), argv: args.map(&:to_s))
|
|
32
|
+
end
|
|
33
|
+
rescue ::Redis::CommandError => error
|
|
34
|
+
if error.message.include?("NOSCRIPT") && !retried
|
|
35
|
+
retried = true
|
|
36
|
+
reload_script(script_name)
|
|
37
|
+
retry
|
|
38
|
+
else
|
|
39
|
+
raise error
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def reload_script(script_name)
|
|
47
|
+
warn "Stoplight is unable to find the script '#{script_name}' in Redis's script cache. Reloading and retrying..."
|
|
48
|
+
@redis.then { |client| client.script(:load, resolve_source(script_name)) }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Redis's Lua sandbox has no `require`, so an included script is spliced in as source text.
|
|
52
|
+
def resolve_source(script_name)
|
|
53
|
+
file_name = "#{script_name}.lua"
|
|
54
|
+
|
|
55
|
+
@scripts_path.each do |path|
|
|
56
|
+
script_path = File.join(path, file_name)
|
|
57
|
+
if File.exist?(script_path)
|
|
58
|
+
source = File.read(script_path)
|
|
59
|
+
return source.gsub(INCLUDE_DIRECTIVE) { resolve_source(T.must(Regexp.last_match(1))) }
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
raise Errno::ENOENT, "No such file #{file_name} @ #{@scripts_path}"
|
|
13
64
|
end
|
|
14
65
|
end
|
|
15
66
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
-- @include now
|
|
2
|
+
|
|
1
3
|
local meta_key = KEYS[1]
|
|
2
|
-
local current_ts =
|
|
4
|
+
local current_ts = now() / 1000
|
|
3
5
|
|
|
4
6
|
-- 1 if the field is a new field in the hash and the value was set
|
|
5
7
|
local became_green = redis.call('HSETNX', meta_key, 'recovered_at', current_ts)
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
-- @include now
|
|
2
|
+
|
|
1
3
|
local meta_key = KEYS[1]
|
|
2
|
-
local
|
|
3
|
-
local
|
|
4
|
+
local recovery_scheduled_after_ts = tonumber(ARGV[1])
|
|
5
|
+
local current_ts = now() / 1000
|
|
4
6
|
|
|
5
7
|
-- 1 if the field is a new field in the hash and the value was set
|
|
6
8
|
local became_red = redis.call('HSETNX', meta_key, 'breached_at', current_ts)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
-- @include now
|
|
2
|
+
|
|
1
3
|
local meta_key = KEYS[1]
|
|
2
|
-
local current_ts =
|
|
4
|
+
local current_ts = now() / 1000
|
|
3
5
|
|
|
4
6
|
-- HSETNX returns 1 if field is new and was set, 0 if field already exists
|
|
5
7
|
local became_yellow = redis.call('HSETNX', meta_key, 'recovery_started_at', current_ts)
|
|
@@ -22,7 +22,7 @@ module Stoplight
|
|
|
22
22
|
# clock: SystemClock.new,
|
|
23
23
|
# redis: Redis.new,
|
|
24
24
|
# scripting: Scripting.new(redis:),
|
|
25
|
-
# key_space
|
|
25
|
+
# key_space:,
|
|
26
26
|
# cool_off_time: 60
|
|
27
27
|
# )
|
|
28
28
|
#
|
|
@@ -46,7 +46,7 @@ module Stoplight
|
|
|
46
46
|
@clock = clock
|
|
47
47
|
@cool_off_time = cool_off_time
|
|
48
48
|
|
|
49
|
-
@state_key = key_space.
|
|
49
|
+
@state_key = key_space.join("state")
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def set_state(state)
|
|
@@ -102,8 +102,8 @@ module Stoplight
|
|
|
102
102
|
#
|
|
103
103
|
def transition_to_green
|
|
104
104
|
became_green = scripting.call(
|
|
105
|
-
|
|
106
|
-
args: [
|
|
105
|
+
"state/transition_to_green",
|
|
106
|
+
args: [],
|
|
107
107
|
keys: [state_key]
|
|
108
108
|
)
|
|
109
109
|
became_green == 1
|
|
@@ -113,8 +113,8 @@ module Stoplight
|
|
|
113
113
|
#
|
|
114
114
|
def transition_to_yellow
|
|
115
115
|
became_yellow = scripting.call(
|
|
116
|
-
|
|
117
|
-
args: [
|
|
116
|
+
"state/transition_to_yellow",
|
|
117
|
+
args: [],
|
|
118
118
|
keys: [state_key]
|
|
119
119
|
)
|
|
120
120
|
became_yellow == 1
|
|
@@ -127,8 +127,8 @@ module Stoplight
|
|
|
127
127
|
recovery_scheduled_after_ts = current_ts + cool_off_time
|
|
128
128
|
|
|
129
129
|
became_red = scripting.call(
|
|
130
|
-
|
|
131
|
-
args: [
|
|
130
|
+
"state/transition_to_red",
|
|
131
|
+
args: [recovery_scheduled_after_ts],
|
|
132
132
|
keys: [state_key]
|
|
133
133
|
)
|
|
134
134
|
|
|
@@ -1,28 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
local failure_json = ARGV[2]
|
|
3
|
-
local metrics_ttl = tonumber(ARGV[3])
|
|
1
|
+
-- @include now
|
|
4
2
|
|
|
5
3
|
local metrics_key = KEYS[1]
|
|
4
|
+
local error_json = ARGV[1]
|
|
5
|
+
local metrics_ttl = tonumber(ARGV[2])
|
|
6
6
|
|
|
7
7
|
-- Update metadata
|
|
8
|
-
local meta = redis.call('HMGET', metrics_key, '
|
|
9
|
-
local
|
|
10
|
-
local
|
|
8
|
+
local meta = redis.call('HMGET', metrics_key, 'consecutive_errors', "last_success_at")
|
|
9
|
+
local prev_consecutive_errors = tonumber(meta[1])
|
|
10
|
+
local last_success_at = meta[2]
|
|
11
|
+
local failure_ts = now() / 1000.0
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
'consecutive_errors', (prev_consecutive_errors or 0) + 1,
|
|
24
|
-
'consecutive_successes', 0
|
|
25
|
-
)
|
|
26
|
-
end
|
|
13
|
+
local consecutive_errors = (prev_consecutive_errors or 0) + 1
|
|
14
|
+
local consecutive_successes = 0
|
|
15
|
+
|
|
16
|
+
-- Always update with current timestamp (out-of-order impossible with Redis time)
|
|
17
|
+
redis.call(
|
|
18
|
+
'HSET', metrics_key,
|
|
19
|
+
'last_error_at', failure_ts,
|
|
20
|
+
'last_error_json', error_json,
|
|
21
|
+
'consecutive_errors', consecutive_errors,
|
|
22
|
+
'consecutive_successes', consecutive_successes
|
|
23
|
+
)
|
|
27
24
|
|
|
28
25
|
redis.call('EXPIRE', metrics_key, metrics_ttl)
|
|
26
|
+
|
|
27
|
+
return {last_success_at, error_json, consecutive_errors, consecutive_successes}
|
|
@@ -1,26 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
local metrics_ttl = tonumber(ARGV[2])
|
|
1
|
+
-- @include now
|
|
3
2
|
|
|
4
3
|
local metrics_key = KEYS[1]
|
|
4
|
+
local metrics_ttl = tonumber(ARGV[1])
|
|
5
5
|
|
|
6
6
|
-- Update metadata
|
|
7
|
-
local
|
|
8
|
-
local
|
|
9
|
-
local prev_consecutive_successes = tonumber(meta[2])
|
|
7
|
+
local prev_consecutive_successes = tonumber(redis.call('HGET', metrics_key, 'consecutive_successes'))
|
|
8
|
+
local request_ts = now() / 1000.0
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
else
|
|
19
|
-
redis.call(
|
|
20
|
-
'HSET', metrics_key,
|
|
21
|
-
'consecutive_errors', 0,
|
|
22
|
-
'consecutive_successes', (prev_consecutive_successes or 0) + 1
|
|
23
|
-
)
|
|
24
|
-
end
|
|
10
|
+
-- Always update with current timestamp (out-of-order impossible with Redis time)
|
|
11
|
+
redis.call(
|
|
12
|
+
'HSET', metrics_key,
|
|
13
|
+
'last_success_at', request_ts,
|
|
14
|
+
'consecutive_errors', 0,
|
|
15
|
+
'consecutive_successes', (prev_consecutive_successes or 0) + 1
|
|
16
|
+
)
|
|
25
17
|
|
|
26
18
|
redis.call('EXPIRE', metrics_key, metrics_ttl)
|
|
@@ -58,7 +58,7 @@ module Stoplight
|
|
|
58
58
|
@clock = clock
|
|
59
59
|
@scripting = scripting
|
|
60
60
|
@redis = redis
|
|
61
|
-
@metrics_key = key_space.
|
|
61
|
+
@metrics_key = key_space.join("metrics")
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
# Get metrics for the current light
|
|
@@ -71,23 +71,15 @@ module Stoplight
|
|
|
71
71
|
)
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
successes: nil, errors: nil,
|
|
76
|
-
consecutive_errors: consecutive_errors.to_i,
|
|
77
|
-
consecutive_successes: consecutive_successes.to_i,
|
|
78
|
-
last_error: deserialize_failure(last_error_json),
|
|
79
|
-
last_success_at: (clock.at(last_success_at.to_f) if last_success_at)
|
|
80
|
-
)
|
|
74
|
+
build_metrics_snapshot(consecutive_errors:, consecutive_successes:, last_error_json:, last_success_at:)
|
|
81
75
|
end
|
|
82
76
|
|
|
83
77
|
# Records successful circuit breaker execution
|
|
84
78
|
#
|
|
85
79
|
def record_success
|
|
86
|
-
timestamp = clock.current_time.to_f
|
|
87
|
-
|
|
88
80
|
scripting.call(
|
|
89
|
-
|
|
90
|
-
args: [
|
|
81
|
+
"unbounded_metrics/record_success",
|
|
82
|
+
args: [metrics_ttl],
|
|
91
83
|
keys: [metrics_key]
|
|
92
84
|
)
|
|
93
85
|
end
|
|
@@ -97,16 +89,18 @@ module Stoplight
|
|
|
97
89
|
def record_failure(exception)
|
|
98
90
|
timestamp = clock.current_time.to_f
|
|
99
91
|
|
|
100
|
-
scripting.call(
|
|
101
|
-
|
|
102
|
-
args: [
|
|
92
|
+
last_success_at, last_error_json, consecutive_errors, consecutive_successes = scripting.call(
|
|
93
|
+
"unbounded_metrics/record_failure",
|
|
94
|
+
args: [serialize_exception(exception, timestamp:), metrics_ttl],
|
|
103
95
|
keys: [metrics_key]
|
|
104
96
|
)
|
|
97
|
+
|
|
98
|
+
build_metrics_snapshot(consecutive_errors:, consecutive_successes:, last_error_json:, last_success_at:)
|
|
105
99
|
end
|
|
106
100
|
|
|
107
101
|
def clear
|
|
108
102
|
redis.with do |client|
|
|
109
|
-
client.hdel(metrics_key, "last_success_at", "last_error_json", "consecutive_errors", "consecutive_successes")
|
|
103
|
+
client.hdel(metrics_key, "last_success_at", "last_error_at", "last_error_json", "consecutive_errors", "consecutive_successes")
|
|
110
104
|
end
|
|
111
105
|
end
|
|
112
106
|
|
|
@@ -116,6 +110,16 @@ module Stoplight
|
|
|
116
110
|
attr_reader :scripting
|
|
117
111
|
attr_reader :metrics_key
|
|
118
112
|
attr_reader :clock
|
|
113
|
+
|
|
114
|
+
def build_metrics_snapshot(consecutive_errors:, consecutive_successes:, last_error_json:, last_success_at:)
|
|
115
|
+
Domain::MetricsSnapshot.new(
|
|
116
|
+
successes: nil, errors: nil,
|
|
117
|
+
consecutive_errors: consecutive_errors.to_i,
|
|
118
|
+
consecutive_successes: consecutive_successes.to_i,
|
|
119
|
+
last_error: deserialize_failure(last_error_json),
|
|
120
|
+
last_success_at: (clock.at(last_success_at.to_f) if last_success_at)
|
|
121
|
+
)
|
|
122
|
+
end
|
|
119
123
|
end
|
|
120
124
|
end
|
|
121
125
|
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
-- Subtracts each evicted bucket's counts from the running totals before deleting it, so
|
|
2
|
+
-- total_successes/total_failures stay exact. Window is the half-open interval
|
|
3
|
+
-- (bucket_ts - window_size, bucket_ts] - events at or before window_start are excluded.
|
|
4
|
+
--
|
|
5
|
+
-- O(K), K = buckets that had writes and are now stale. K <= window_size in steady state,
|
|
6
|
+
-- but a long idle gap can dump the whole backlog into one call on the next write.
|
|
7
|
+
--
|
|
8
|
+
-- HMGET/HDEL splat fields through unpack(), capped at 8000 args - verified across every
|
|
9
|
+
-- Redis/Valkey version this gem supports - so eviction runs in fixed-size batches.
|
|
10
|
+
-- ZRANGE/ZREMRANGEBYSCORE aren't variadic and skip that limit; keeping both in the same
|
|
11
|
+
-- atomic script call as the batched loop means ZREMRANGEBYSCORE always deletes exactly
|
|
12
|
+
-- what ZRANGE read.
|
|
13
|
+
local EVICT_BATCH_SIZE = 1000
|
|
14
|
+
|
|
15
|
+
local function evict_buckets(metrics_key, ts_index_key, window_start)
|
|
16
|
+
local buckets = redis.call('ZRANGE', ts_index_key, '-inf', window_start, 'BYSCORE')
|
|
17
|
+
if #buckets == 0 then
|
|
18
|
+
return
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
for from = 1, #buckets, EVICT_BATCH_SIZE do
|
|
22
|
+
local to = math.min(from + EVICT_BATCH_SIZE - 1, #buckets)
|
|
23
|
+
|
|
24
|
+
local fields = {}
|
|
25
|
+
for i = from, to do
|
|
26
|
+
fields[#fields + 1] = buckets[i] .. ':f'
|
|
27
|
+
fields[#fields + 1] = buckets[i] .. ':s'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
local values = redis.call('HMGET', metrics_key, unpack(fields))
|
|
31
|
+
|
|
32
|
+
local failures, successes = 0, 0
|
|
33
|
+
for i = 1, #values, 2 do
|
|
34
|
+
failures = failures + (tonumber(values[i]) or 0)
|
|
35
|
+
successes = successes + (tonumber(values[i + 1]) or 0)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
redis.call('HINCRBY', metrics_key, 'total_failures', -failures)
|
|
39
|
+
redis.call('HINCRBY', metrics_key, 'total_successes', -successes)
|
|
40
|
+
redis.call('HDEL', metrics_key, unpack(fields))
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
redis.call('ZREMRANGEBYSCORE', ts_index_key, '-inf', window_start)
|
|
44
|
+
end
|
|
@@ -1,26 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
local window_end_ts = tonumber(ARGV[3])
|
|
4
|
-
local metrics_fields = {}
|
|
5
|
-
for idx = 4, #ARGV do
|
|
6
|
-
table.insert(metrics_fields, ARGV[idx])
|
|
7
|
-
end
|
|
1
|
+
-- @include now
|
|
2
|
+
-- @include window_metrics/_evict
|
|
8
3
|
|
|
9
|
-
local
|
|
4
|
+
local window_size = tonumber(ARGV[1])
|
|
10
5
|
|
|
11
|
-
local
|
|
12
|
-
|
|
13
|
-
for idx = start_idx, start_idx + bucket_count - 1 do
|
|
14
|
-
total = total + tonumber(redis.call('ZCOUNT', KEYS[idx], start_ts, window_end_ts))
|
|
15
|
-
end
|
|
16
|
-
return total
|
|
17
|
-
end
|
|
6
|
+
local metrics_key = KEYS[1]
|
|
7
|
+
local ts_index_key = KEYS[2]
|
|
18
8
|
|
|
19
|
-
local
|
|
20
|
-
|
|
9
|
+
local current_ts = now() / 1000.0
|
|
10
|
+
evict_buckets(metrics_key, ts_index_key, math.floor(current_ts) - window_size)
|
|
21
11
|
|
|
22
|
-
|
|
23
|
-
local
|
|
12
|
+
-- copy arguments starting from index 2 to fields' tail
|
|
13
|
+
local fields = {'total_successes','total_failures', unpack(ARGV, 2) }
|
|
14
|
+
local metrics = redis.call('HMGET', metrics_key, unpack(fields))
|
|
24
15
|
|
|
25
|
-
|
|
26
|
-
|
|
16
|
+
metrics[1] = tonumber(metrics[1]) or 0 -- total_successes
|
|
17
|
+
metrics[2] = tonumber(metrics[2]) or 0 -- total_failures
|
|
18
|
+
|
|
19
|
+
return metrics
|
|
@@ -1,36 +1,38 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
local
|
|
5
|
-
local
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
local
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
1
|
+
-- @include now
|
|
2
|
+
-- @include window_metrics/_evict
|
|
3
|
+
|
|
4
|
+
local failure_json = ARGV[1]
|
|
5
|
+
local window_size = tonumber(ARGV[2])
|
|
6
|
+
local metadata_ttl = tonumber(ARGV[3])
|
|
7
|
+
|
|
8
|
+
local metrics_key = KEYS[1]
|
|
9
|
+
local ts_index_key = KEYS[2]
|
|
10
|
+
local request_ts = now() / 1000.0
|
|
11
|
+
local bucket_ts = math.floor(request_ts)
|
|
12
|
+
|
|
13
|
+
evict_buckets(metrics_key, ts_index_key, bucket_ts - window_size)
|
|
14
|
+
|
|
15
|
+
local bucket = 'bucket:' .. bucket_ts
|
|
16
|
+
redis.call('HINCRBY', metrics_key, bucket .. ':f', 1)
|
|
17
|
+
redis.call('HINCRBY', metrics_key, 'total_failures', 1)
|
|
18
|
+
redis.call('ZADD', ts_index_key, bucket_ts, bucket)
|
|
19
|
+
|
|
20
|
+
local consecutive_errors = redis.call('HINCRBY', metrics_key, 'consecutive_errors', 1)
|
|
21
|
+
|
|
22
|
+
-- Always update with current timestamp (out-of-order impossible with Redis time)
|
|
23
|
+
redis.call(
|
|
24
|
+
'HSET', metrics_key,
|
|
25
|
+
'last_error_at', request_ts,
|
|
26
|
+
'last_error_json', failure_json,
|
|
27
|
+
'consecutive_successes', 0
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
redis.call('EXPIRE', metrics_key, metadata_ttl)
|
|
31
|
+
redis.call('EXPIRE', ts_index_key, metadata_ttl)
|
|
32
|
+
|
|
33
|
+
local result = redis.call('HMGET', metrics_key, 'last_success_at', 'total_successes', 'total_failures')
|
|
34
|
+
local last_success_at = result[1]
|
|
35
|
+
local total_successes = tonumber(result[2]) or 0
|
|
36
|
+
local total_failures = tonumber(result[3]) or 0
|
|
37
|
+
|
|
38
|
+
return {total_successes, total_failures, last_success_at, failure_json, consecutive_errors, 0}
|
|
@@ -1,35 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
local bucket_ttl = tonumber(ARGV[3])
|
|
4
|
-
local metadata_ttl = tonumber(ARGV[4])
|
|
1
|
+
-- @include now
|
|
2
|
+
-- @include window_metrics/_evict
|
|
5
3
|
|
|
6
|
-
local
|
|
7
|
-
local
|
|
4
|
+
local window_size = tonumber(ARGV[1])
|
|
5
|
+
local metadata_ttl = tonumber(ARGV[2])
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
end
|
|
7
|
+
local metrics_key = KEYS[1]
|
|
8
|
+
local ts_index_key = KEYS[2]
|
|
9
|
+
local request_ts = now() / 1000.0
|
|
10
|
+
local bucket_ts = math.floor(request_ts)
|
|
14
11
|
|
|
15
|
-
|
|
16
|
-
local meta = redis.call('HMGET', metrics_key, 'last_success_at', 'consecutive_successes')
|
|
17
|
-
local prev_success_ts = tonumber(meta[1])
|
|
18
|
-
local prev_consecutive_successes = tonumber(meta[2])
|
|
12
|
+
evict_buckets(metrics_key, ts_index_key, bucket_ts - window_size)
|
|
19
13
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
'consecutive_errors', 0,
|
|
25
|
-
'consecutive_successes', (prev_consecutive_successes or 0) + 1
|
|
26
|
-
)
|
|
27
|
-
else
|
|
28
|
-
redis.call(
|
|
29
|
-
'HSET', metrics_key,
|
|
30
|
-
'consecutive_errors', 0,
|
|
31
|
-
'consecutive_successes', (prev_consecutive_successes or 0) + 1
|
|
32
|
-
)
|
|
33
|
-
end
|
|
14
|
+
local bucket = 'bucket:' .. bucket_ts
|
|
15
|
+
redis.call('HINCRBY', metrics_key, bucket .. ':s', 1)
|
|
16
|
+
redis.call('HINCRBY', metrics_key, 'total_successes', 1)
|
|
17
|
+
redis.call('ZADD', ts_index_key, bucket_ts, bucket)
|
|
34
18
|
|
|
35
|
-
|
|
19
|
+
-- Always update with current timestamp (out-of-order impossible with Redis time)
|
|
20
|
+
redis.call(
|
|
21
|
+
'HSET', metrics_key,
|
|
22
|
+
'last_success_at', request_ts,
|
|
23
|
+
'consecutive_errors', 0
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
redis.call('HINCRBY', metrics_key, 'consecutive_successes', 1)
|
|
27
|
+
redis.call('EXPIRE', metrics_key, metadata_ttl)
|
|
28
|
+
redis.call('EXPIRE', ts_index_key, metadata_ttl)
|