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,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stoplight
|
|
4
|
+
module Domain
|
|
5
|
+
module Telemetry
|
|
6
|
+
# In-process telemetry bus
|
|
7
|
+
class Bus
|
|
8
|
+
# Value-level mirror of the +event+ union.
|
|
9
|
+
EVENT_CLASSES = [
|
|
10
|
+
RunCompleted,
|
|
11
|
+
TrafficBreached,
|
|
12
|
+
RecoveryStarted,
|
|
13
|
+
RecoverySucceeded,
|
|
14
|
+
RecoveryFailed,
|
|
15
|
+
LockChanged,
|
|
16
|
+
RecoveryProbeCompleted,
|
|
17
|
+
LightRegistered
|
|
18
|
+
].freeze
|
|
19
|
+
|
|
20
|
+
MAX_SUBSCRIPTIONS = 1_000
|
|
21
|
+
|
|
22
|
+
def initialize(error_notifier:, max_subscriptions: MAX_SUBSCRIPTIONS)
|
|
23
|
+
@mutex = Mutex.new
|
|
24
|
+
@error_notifier = error_notifier
|
|
25
|
+
@max_subscriptions = max_subscriptions
|
|
26
|
+
@subscriptions = []
|
|
27
|
+
rebuild
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def subscribe(filter = nil, &handler)
|
|
31
|
+
raise ArgumentError, "nothing to subscribe. Please, pass a block into `Telemetry#subscribe`" unless handler
|
|
32
|
+
raise ArgumentError, "filter must be nil or a Module, got #{filter.inspect}" unless filter.nil? || filter.is_a?(Module)
|
|
33
|
+
unless filter.nil? || EVENT_CLASSES.any? { |event_class| event_class <= filter }
|
|
34
|
+
raise ArgumentError, "filter #{filter.inspect} does not match any telemetry event class"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
subscription = Subscription.new
|
|
38
|
+
@mutex.synchronize do
|
|
39
|
+
if @subscriptions.size >= @max_subscriptions
|
|
40
|
+
raise Stoplight::Error::TooManySubscriptions, "exceeded #{@max_subscriptions} telemetry subscriptions"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
@subscriptions << [subscription, filter, handler]
|
|
44
|
+
rebuild
|
|
45
|
+
end
|
|
46
|
+
subscription
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def unsubscribe(subscription)
|
|
50
|
+
@mutex.synchronize do
|
|
51
|
+
@subscriptions.reject! { |token, _, _| token.equal?(subscription) }
|
|
52
|
+
rebuild
|
|
53
|
+
end
|
|
54
|
+
nil
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def subscribed?(event_class)
|
|
58
|
+
@dispatch.key?(event_class)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def publish(envelope)
|
|
62
|
+
@dispatch[envelope.payload.class]&.each do |handler|
|
|
63
|
+
handler.call(envelope)
|
|
64
|
+
rescue => error
|
|
65
|
+
begin
|
|
66
|
+
@error_notifier.call(error)
|
|
67
|
+
rescue => notifier_error
|
|
68
|
+
warn "Stoplight telemetry error_notifier raised: #{notifier_error.message}"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
nil
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Called under @mutex. Resolves every filter (nil = firehose, module, or exact class) against the closed set of
|
|
75
|
+
# concrete classes and swaps in a frozen table - copy-on-write, so publish never sees a table mid-mutation and
|
|
76
|
+
# needs no lock.
|
|
77
|
+
private def rebuild
|
|
78
|
+
table = {} #: Hash[Class, Array[untyped]]
|
|
79
|
+
EVENT_CLASSES.each do |event_class|
|
|
80
|
+
handlers = @subscriptions.filter_map do |_, filter, handler|
|
|
81
|
+
handler if filter.nil? || event_class <= filter
|
|
82
|
+
end
|
|
83
|
+
table[event_class] = handlers.freeze unless handlers.empty?
|
|
84
|
+
end
|
|
85
|
+
@dispatch = table.freeze
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stoplight
|
|
4
|
+
module Domain
|
|
5
|
+
module Telemetry
|
|
6
|
+
# Consumer-only view of a telemetry bus - forwards subscribe/unsubscribe, never publish.
|
|
7
|
+
class Consumer
|
|
8
|
+
def initialize(telemetry)
|
|
9
|
+
@telemetry = telemetry
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def subscribe(...) = @telemetry.subscribe(...)
|
|
13
|
+
|
|
14
|
+
def unsubscribe(...) = @telemetry.unsubscribe(...)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stoplight
|
|
4
|
+
module Domain
|
|
5
|
+
module Telemetry
|
|
6
|
+
class Emitter
|
|
7
|
+
def initialize(bus:, clock:, system_name:, light_name:, error_notifier:)
|
|
8
|
+
@bus = bus
|
|
9
|
+
@clock = clock
|
|
10
|
+
@system_name = system_name
|
|
11
|
+
@light_name = light_name
|
|
12
|
+
@error_notifier = error_notifier
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# True when any subscriber would receive this event class.
|
|
16
|
+
def subscribed?(event_class) = @bus.subscribed?(event_class)
|
|
17
|
+
|
|
18
|
+
# Emits telemetry event. A failure to build or publish it is routed to the error
|
|
19
|
+
# notifier, never to the caller - the same isolation the bus gives subscriber handlers.
|
|
20
|
+
def emit(event_class)
|
|
21
|
+
return unless subscribed?(event_class)
|
|
22
|
+
|
|
23
|
+
@bus.publish(
|
|
24
|
+
Envelope.new(
|
|
25
|
+
light_name: @light_name,
|
|
26
|
+
system_name: @system_name,
|
|
27
|
+
occurred_at: @clock.current_time,
|
|
28
|
+
payload: yield
|
|
29
|
+
)
|
|
30
|
+
)
|
|
31
|
+
rescue => error
|
|
32
|
+
notify_error(error)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def notify_error(error)
|
|
38
|
+
@error_notifier.call(error)
|
|
39
|
+
rescue => notifier_error
|
|
40
|
+
warn "Stoplight telemetry error_notifier raised: #{notifier_error.message}"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stoplight
|
|
4
|
+
module Domain
|
|
5
|
+
module Telemetry
|
|
6
|
+
# Emitted once per (process instance, system, light) when the light's configuration first materializes.
|
|
7
|
+
LightRegistered = Data.define(
|
|
8
|
+
:settings
|
|
9
|
+
)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stoplight
|
|
4
|
+
module Domain
|
|
5
|
+
module Telemetry
|
|
6
|
+
# state_transitioned variant: manual lock override changed.
|
|
7
|
+
LockChanged = Data.define(
|
|
8
|
+
:from_color,
|
|
9
|
+
:to_color,
|
|
10
|
+
:from_state,
|
|
11
|
+
:to_state
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
class LockChanged
|
|
15
|
+
include StateTransitioned
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stoplight
|
|
4
|
+
module Domain
|
|
5
|
+
module Telemetry
|
|
6
|
+
# The serializable subset of MetricsSnapshot.
|
|
7
|
+
Metrics = Data.define(
|
|
8
|
+
:successes,
|
|
9
|
+
:errors,
|
|
10
|
+
:consecutive_errors,
|
|
11
|
+
:consecutive_successes
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stoplight
|
|
4
|
+
module Domain
|
|
5
|
+
module Telemetry
|
|
6
|
+
# state_transitioned variant: recovery policy sent the light back to red.
|
|
7
|
+
RecoveryFailed = Data.define(
|
|
8
|
+
:from_color,
|
|
9
|
+
:to_color,
|
|
10
|
+
:policy,
|
|
11
|
+
:failure,
|
|
12
|
+
:metrics
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
class RecoveryFailed
|
|
16
|
+
include StateTransitioned
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stoplight
|
|
4
|
+
module Domain
|
|
5
|
+
module Telemetry
|
|
6
|
+
# Emitted for every recovery probe (a run executed while yellow, under the recovery lock).
|
|
7
|
+
RecoveryProbeCompleted = Data.define(
|
|
8
|
+
:outcome,
|
|
9
|
+
:duration_ms,
|
|
10
|
+
:failure,
|
|
11
|
+
:progress
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stoplight
|
|
4
|
+
module Domain
|
|
5
|
+
module Telemetry
|
|
6
|
+
# state_transitioned variant: cool-off elapsed and the first probe explicitly entered recovery.
|
|
7
|
+
RecoveryStarted = Data.define(
|
|
8
|
+
:from_color,
|
|
9
|
+
:to_color,
|
|
10
|
+
:breached_at
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
class RecoveryStarted
|
|
14
|
+
include StateTransitioned
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stoplight
|
|
4
|
+
module Domain
|
|
5
|
+
module Telemetry
|
|
6
|
+
# state_transitioned variant: recovery policy resumed traffic.
|
|
7
|
+
RecoverySucceeded = Data.define(
|
|
8
|
+
:from_color,
|
|
9
|
+
:to_color,
|
|
10
|
+
:policy,
|
|
11
|
+
:metrics
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
class RecoverySucceeded
|
|
15
|
+
include StateTransitioned
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stoplight
|
|
4
|
+
module Domain
|
|
5
|
+
module Telemetry
|
|
6
|
+
# Emitted for every Light#run.
|
|
7
|
+
RunCompleted = Data.define(
|
|
8
|
+
:outcome,
|
|
9
|
+
:color,
|
|
10
|
+
:duration_ms,
|
|
11
|
+
:failure,
|
|
12
|
+
:fallback_used,
|
|
13
|
+
:retry_after
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stoplight
|
|
4
|
+
module Domain
|
|
5
|
+
module Telemetry
|
|
6
|
+
# Builds and emits RunCompleted events for one light color.
|
|
7
|
+
#
|
|
8
|
+
# @api private
|
|
9
|
+
class RunRecorder
|
|
10
|
+
def initialize(emitter:, color:)
|
|
11
|
+
@emitter = emitter
|
|
12
|
+
@color = color
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# True when any subscriber would receive a RunCompleted event.
|
|
16
|
+
def subscribed? = @emitter.subscribed?(RunCompleted)
|
|
17
|
+
|
|
18
|
+
def record_success(duration_ms:, error: nil)
|
|
19
|
+
emit(
|
|
20
|
+
outcome: :success,
|
|
21
|
+
duration_ms:,
|
|
22
|
+
failure: error && Failure.new(exception: error, tracked: false),
|
|
23
|
+
fallback_used: false,
|
|
24
|
+
retry_after: nil
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def record_failure(error, duration_ms:, fallback_used:)
|
|
29
|
+
emit(
|
|
30
|
+
outcome: :failure,
|
|
31
|
+
duration_ms:,
|
|
32
|
+
failure: Failure.new(exception: error, tracked: true),
|
|
33
|
+
fallback_used:,
|
|
34
|
+
retry_after: nil
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def record_blocked(fallback_used:, retry_after:)
|
|
39
|
+
emit(
|
|
40
|
+
outcome: :blocked,
|
|
41
|
+
duration_ms: nil,
|
|
42
|
+
failure: nil,
|
|
43
|
+
fallback_used:,
|
|
44
|
+
retry_after:
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def emit(outcome:, duration_ms:, failure:, fallback_used:, retry_after:)
|
|
51
|
+
@emitter.emit(RunCompleted) do
|
|
52
|
+
RunCompleted.new(outcome:, color: @color, duration_ms:, failure:, fallback_used:, retry_after:)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stoplight
|
|
4
|
+
module Domain
|
|
5
|
+
module Telemetry
|
|
6
|
+
# The serializable subset of a light's configuration.
|
|
7
|
+
Settings = Data.define(
|
|
8
|
+
:cool_off_time,
|
|
9
|
+
:threshold,
|
|
10
|
+
:recovery_threshold,
|
|
11
|
+
:window_size,
|
|
12
|
+
:tracked_errors,
|
|
13
|
+
:skipped_errors,
|
|
14
|
+
:traffic_control,
|
|
15
|
+
:traffic_control_params,
|
|
16
|
+
:traffic_recovery,
|
|
17
|
+
:traffic_recovery_params
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stoplight
|
|
4
|
+
module Domain
|
|
5
|
+
module Telemetry
|
|
6
|
+
# state_transitioned variant: traffic control tripped the light.
|
|
7
|
+
TrafficBreached = Data.define(
|
|
8
|
+
:from_color,
|
|
9
|
+
:to_color,
|
|
10
|
+
:policy,
|
|
11
|
+
:failure,
|
|
12
|
+
:metrics
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
class TrafficBreached
|
|
16
|
+
include StateTransitioned
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -4,54 +4,98 @@ module Stoplight
|
|
|
4
4
|
module Domain
|
|
5
5
|
module Tracker
|
|
6
6
|
class RecoveryProbe
|
|
7
|
-
def initialize(traffic_recovery:,
|
|
7
|
+
def initialize(traffic_recovery:, config:, metrics_store:, state_store:, emitter:)
|
|
8
8
|
@traffic_recovery = traffic_recovery
|
|
9
|
-
@notifiers = notifiers
|
|
10
9
|
@config = config
|
|
11
10
|
@metrics_store = metrics_store
|
|
12
11
|
@state_store = state_store
|
|
12
|
+
@emitter = emitter
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
def record_failure(exception)
|
|
15
|
+
def record_failure(exception, duration_ms:)
|
|
17
16
|
metrics_store.record_failure(exception)
|
|
18
17
|
|
|
19
|
-
recover
|
|
18
|
+
recover(duration_ms:, exception:)
|
|
20
19
|
end
|
|
21
20
|
|
|
22
|
-
def record_success
|
|
21
|
+
def record_success(duration_ms:)
|
|
23
22
|
metrics_store.record_success
|
|
24
23
|
|
|
25
|
-
recover
|
|
24
|
+
recover(duration_ms:, exception: nil)
|
|
26
25
|
end
|
|
27
26
|
|
|
28
27
|
private
|
|
29
28
|
|
|
30
29
|
attr_reader :traffic_recovery
|
|
31
|
-
attr_reader :notifiers
|
|
32
30
|
attr_reader :config
|
|
33
31
|
attr_reader :metrics_store
|
|
34
32
|
attr_reader :state_store
|
|
33
|
+
attr_reader :emitter
|
|
35
34
|
|
|
36
|
-
def recover
|
|
35
|
+
def recover(duration_ms:, exception:)
|
|
37
36
|
recovery_metrics = metrics_store.metrics_snapshot
|
|
37
|
+
|
|
38
|
+
emitter.emit(Telemetry::RecoveryProbeCompleted) do
|
|
39
|
+
failure = exception ? Telemetry::Failure.new(exception:, tracked: true) : nil
|
|
40
|
+
Telemetry::RecoveryProbeCompleted.new(
|
|
41
|
+
outcome: failure ? :failure : :success,
|
|
42
|
+
duration_ms:,
|
|
43
|
+
failure:,
|
|
44
|
+
progress: Telemetry::Metrics.new(
|
|
45
|
+
successes: recovery_metrics.successes,
|
|
46
|
+
errors: recovery_metrics.errors,
|
|
47
|
+
consecutive_errors: recovery_metrics.consecutive_errors,
|
|
48
|
+
consecutive_successes: recovery_metrics.consecutive_successes
|
|
49
|
+
)
|
|
50
|
+
)
|
|
51
|
+
end
|
|
52
|
+
|
|
38
53
|
recovery_result = traffic_recovery.determine_color(config, recovery_metrics)
|
|
39
54
|
|
|
40
55
|
return if recovery_result == TrafficRecovery::YELLOW
|
|
41
56
|
|
|
42
|
-
|
|
43
|
-
when TrafficRecovery::GREEN
|
|
44
|
-
|
|
57
|
+
case recovery_result
|
|
58
|
+
when TrafficRecovery::GREEN
|
|
59
|
+
to_color = Color::GREEN
|
|
60
|
+
if transition(to_color:)
|
|
61
|
+
emitter.emit(Telemetry::RecoverySucceeded) do
|
|
62
|
+
Telemetry::RecoverySucceeded.new(from_color: Color::YELLOW, to_color:,
|
|
63
|
+
policy: traffic_recovery.name,
|
|
64
|
+
metrics: Telemetry::Metrics.new(
|
|
65
|
+
successes: recovery_metrics.successes,
|
|
66
|
+
errors: recovery_metrics.errors,
|
|
67
|
+
consecutive_errors: recovery_metrics.consecutive_errors,
|
|
68
|
+
consecutive_successes: recovery_metrics.consecutive_successes
|
|
69
|
+
))
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
when TrafficRecovery::RED
|
|
73
|
+
to_color = Color::RED
|
|
74
|
+
if transition(to_color:)
|
|
75
|
+
emitter.emit(Telemetry::RecoveryFailed) do
|
|
76
|
+
Telemetry::RecoveryFailed.new(
|
|
77
|
+
from_color: Color::YELLOW,
|
|
78
|
+
to_color:,
|
|
79
|
+
policy: traffic_recovery.name,
|
|
80
|
+
failure: exception ? Telemetry::Failure.new(exception:, tracked: true) : nil,
|
|
81
|
+
metrics: Telemetry::Metrics.new(
|
|
82
|
+
successes: recovery_metrics.successes,
|
|
83
|
+
errors: recovery_metrics.errors,
|
|
84
|
+
consecutive_errors: recovery_metrics.consecutive_errors,
|
|
85
|
+
consecutive_successes: recovery_metrics.consecutive_successes
|
|
86
|
+
)
|
|
87
|
+
)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
45
90
|
else
|
|
46
91
|
raise "recovery strategy returned unexpected color: #{recovery_result}"
|
|
47
92
|
end
|
|
93
|
+
end
|
|
48
94
|
|
|
49
|
-
|
|
95
|
+
def transition(to_color:)
|
|
96
|
+
return false unless state_store.transition_to_color(to_color)
|
|
50
97
|
metrics_store.clear
|
|
51
|
-
|
|
52
|
-
notifiers.each do |notifier|
|
|
53
|
-
notifier.notify(info, from_color, to_color, nil)
|
|
54
|
-
end
|
|
98
|
+
true
|
|
55
99
|
end
|
|
56
100
|
end
|
|
57
101
|
end
|
|
@@ -10,17 +10,16 @@ module Stoplight
|
|
|
10
10
|
#
|
|
11
11
|
# @api private
|
|
12
12
|
class Request
|
|
13
|
-
def initialize(traffic_control:,
|
|
13
|
+
def initialize(traffic_control:, config:, metrics_store:, state_store:, emitter:)
|
|
14
14
|
@traffic_control = traffic_control
|
|
15
|
-
@notifiers = notifiers
|
|
16
15
|
@config = config
|
|
17
16
|
@metrics_store = metrics_store
|
|
18
17
|
@state_store = state_store
|
|
18
|
+
@emitter = emitter
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def record_failure(exception)
|
|
22
|
-
metrics_store.record_failure(exception)
|
|
23
|
-
metrics = metrics_store.metrics_snapshot
|
|
22
|
+
metrics = metrics_store.record_failure(exception)
|
|
24
23
|
|
|
25
24
|
transition_to_red(exception, metrics:)
|
|
26
25
|
end
|
|
@@ -30,19 +29,29 @@ module Stoplight
|
|
|
30
29
|
private
|
|
31
30
|
|
|
32
31
|
attr_reader :traffic_control
|
|
33
|
-
attr_reader :notifiers
|
|
34
32
|
attr_reader :config
|
|
35
33
|
attr_reader :metrics_store
|
|
36
34
|
attr_reader :state_store
|
|
35
|
+
attr_reader :emitter
|
|
37
36
|
|
|
38
37
|
def transition_to_red(exception, metrics:)
|
|
39
38
|
if traffic_control.stop_traffic?(config, metrics)
|
|
40
39
|
# Returns true only if not yet in red therefore preventing
|
|
41
40
|
# duplicate notifications
|
|
42
41
|
if state_store.transition_to_color(Color::RED)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
emitter.emit(Telemetry::TrafficBreached) do
|
|
43
|
+
Telemetry::TrafficBreached.new(
|
|
44
|
+
from_color: Color::GREEN,
|
|
45
|
+
to_color: Color::RED,
|
|
46
|
+
policy: traffic_control.name,
|
|
47
|
+
failure: Telemetry::Failure.new(exception:, tracked: true),
|
|
48
|
+
metrics: Telemetry::Metrics.new(
|
|
49
|
+
successes: metrics.successes,
|
|
50
|
+
errors: metrics.errors,
|
|
51
|
+
consecutive_errors: metrics.consecutive_errors,
|
|
52
|
+
consecutive_successes: metrics.consecutive_successes
|
|
53
|
+
)
|
|
54
|
+
)
|
|
46
55
|
end
|
|
47
56
|
end
|
|
48
57
|
end
|
|
@@ -27,11 +27,13 @@ module Stoplight
|
|
|
27
27
|
# Will switch to red only if 5 consecutive failures occur regardless of the time window
|
|
28
28
|
# @api private
|
|
29
29
|
class ConsecutiveErrors
|
|
30
|
+
NAME = :consecutive_errors
|
|
31
|
+
|
|
30
32
|
def check_compatibility(config)
|
|
31
|
-
if config.threshold
|
|
32
|
-
CompatibilityResult.incompatible("`threshold` should be bigger than 0")
|
|
33
|
-
elsif !config.threshold.is_a?(Integer)
|
|
33
|
+
if !config.threshold.is_a?(Integer)
|
|
34
34
|
CompatibilityResult.incompatible("`threshold` should be an integer")
|
|
35
|
+
elsif config.threshold <= 0
|
|
36
|
+
CompatibilityResult.incompatible("`threshold` should be bigger than 0")
|
|
35
37
|
else
|
|
36
38
|
CompatibilityResult.compatible
|
|
37
39
|
end
|
|
@@ -41,9 +43,17 @@ module Stoplight
|
|
|
41
43
|
metrics.consecutive_errors >= config.threshold
|
|
42
44
|
end
|
|
43
45
|
|
|
46
|
+
def name = NAME.to_s
|
|
47
|
+
|
|
48
|
+
def hash = self.class.hash
|
|
49
|
+
|
|
44
50
|
def ==(other)
|
|
45
51
|
other.is_a?(self.class)
|
|
46
52
|
end
|
|
53
|
+
|
|
54
|
+
def eql?(other)
|
|
55
|
+
self == other
|
|
56
|
+
end
|
|
47
57
|
end
|
|
48
58
|
end
|
|
49
59
|
end
|