stoplight 5.7.0 → 5.8.0
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/README.md +1 -1
- data/UPGRADING.md +303 -0
- data/lib/generators/stoplight/install/install_generator.rb +6 -1
- data/lib/stoplight/admin/dependencies.rb +1 -1
- data/lib/stoplight/admin/helpers.rb +20 -4
- data/lib/stoplight/admin/lights_repository/light.rb +22 -6
- data/lib/stoplight/admin/lights_repository.rb +6 -5
- data/lib/stoplight/admin/views/_card.erb +8 -5
- data/lib/stoplight/color.rb +9 -0
- data/lib/stoplight/data_store.rb +28 -0
- data/lib/stoplight/domain/compatibility_result.rb +7 -7
- data/lib/stoplight/domain/config.rb +38 -39
- data/lib/stoplight/domain/error_tracking_policy.rb +27 -0
- data/lib/stoplight/domain/failure.rb +1 -1
- data/lib/stoplight/domain/light/configuration_builder_interface.rb +2 -0
- data/lib/stoplight/domain/light.rb +15 -46
- data/lib/stoplight/domain/light_info.rb +7 -0
- data/lib/stoplight/domain/metrics_snapshot.rb +58 -0
- data/lib/stoplight/domain/state_snapshot.rb +29 -23
- data/lib/stoplight/domain/storage/recovery_lock_token.rb +15 -0
- data/lib/stoplight/domain/strategies/green_run_strategy.rb +18 -26
- data/lib/stoplight/domain/strategies/red_run_strategy.rb +9 -12
- data/lib/stoplight/domain/strategies/yellow_run_strategy.rb +41 -51
- data/lib/stoplight/domain/tracker/recovery_probe.rb +16 -33
- data/lib/stoplight/domain/tracker/request.rb +12 -31
- data/lib/stoplight/domain/traffic_control/consecutive_errors.rb +8 -11
- data/lib/stoplight/domain/traffic_control/error_rate.rb +19 -15
- data/lib/stoplight/domain/traffic_recovery/consecutive_successes.rb +6 -10
- data/lib/stoplight/domain/traffic_recovery.rb +3 -4
- data/lib/stoplight/error.rb +46 -0
- data/lib/stoplight/infrastructure/{data_store/fail_safe.rb → fail_safe/data_store.rb} +39 -51
- data/lib/stoplight/infrastructure/fail_safe/storage/metrics.rb +65 -0
- data/lib/stoplight/infrastructure/fail_safe/storage/recovery_lock.rb +69 -0
- data/lib/stoplight/infrastructure/fail_safe/storage/recovery_lock_token.rb +19 -0
- data/lib/stoplight/infrastructure/fail_safe/storage/state.rb +62 -0
- data/lib/stoplight/infrastructure/{data_store/memory → memory/data_store}/metrics.rb +2 -2
- data/lib/stoplight/infrastructure/{data_store/memory → memory/data_store}/recovery_lock_store.rb +10 -12
- data/lib/stoplight/infrastructure/{data_store/memory → memory/data_store}/recovery_lock_token.rb +3 -6
- data/lib/stoplight/infrastructure/{data_store/memory → memory/data_store}/sliding_window.rb +21 -26
- data/lib/stoplight/infrastructure/{data_store/memory → memory/data_store}/state.rb +3 -3
- data/lib/stoplight/infrastructure/{data_store/memory.rb → memory/data_store.rb} +36 -32
- data/lib/stoplight/infrastructure/memory/storage/recovery_lock.rb +35 -0
- data/lib/stoplight/infrastructure/memory/storage/recovery_metrics.rb +16 -0
- data/lib/stoplight/infrastructure/memory/storage/state.rb +155 -0
- data/lib/stoplight/infrastructure/memory/storage/unbounded_metrics.rb +103 -0
- data/lib/stoplight/infrastructure/memory/storage/window_metrics.rb +101 -0
- data/lib/stoplight/infrastructure/notifier/fail_safe.rb +9 -21
- data/lib/stoplight/infrastructure/notifier/generic.rb +4 -14
- data/lib/stoplight/infrastructure/notifier/io.rb +1 -2
- data/lib/stoplight/infrastructure/notifier/logger.rb +1 -2
- data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/recovery_lock_store.rb +9 -22
- data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/recovery_lock_token.rb +7 -14
- data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/scripting.rb +22 -20
- data/lib/stoplight/infrastructure/{data_store/redis.rb → redis/data_store.rb} +48 -56
- data/lib/stoplight/infrastructure/redis/storage/key_space.rb +51 -0
- data/lib/stoplight/infrastructure/redis/storage/metrics.rb +40 -0
- data/lib/stoplight/infrastructure/redis/storage/recovery_lock/release_lock.lua +6 -0
- data/lib/stoplight/infrastructure/redis/storage/recovery_lock.rb +64 -0
- data/lib/stoplight/infrastructure/redis/storage/recovery_metrics.rb +20 -0
- data/lib/stoplight/infrastructure/redis/storage/scripting.rb +18 -0
- data/lib/stoplight/infrastructure/redis/storage/state/transition_to_green.lua +10 -0
- data/lib/stoplight/infrastructure/redis/storage/state/transition_to_red.lua +10 -0
- data/lib/stoplight/infrastructure/redis/storage/state/transition_to_yellow.lua +9 -0
- data/lib/stoplight/infrastructure/redis/storage/state.rb +141 -0
- data/lib/stoplight/infrastructure/redis/storage/unbounded_metrics/record_failure.lua +28 -0
- data/lib/stoplight/infrastructure/redis/storage/unbounded_metrics/record_success.lua +26 -0
- data/lib/stoplight/infrastructure/redis/storage/unbounded_metrics.rb +123 -0
- data/lib/stoplight/infrastructure/redis/storage/window_metrics/metrics_snapshot.lua +26 -0
- data/lib/stoplight/infrastructure/redis/storage/window_metrics/record_failure.lua +36 -0
- data/lib/stoplight/infrastructure/redis/storage/window_metrics/record_success.lua +35 -0
- data/lib/stoplight/infrastructure/redis/storage/window_metrics.rb +174 -0
- data/lib/stoplight/infrastructure/storage/compatibility_metrics.rb +3 -10
- data/lib/stoplight/infrastructure/storage/compatibility_recovery_lock.rb +8 -11
- data/lib/stoplight/infrastructure/storage/compatibility_recovery_metrics.rb +6 -14
- data/lib/stoplight/infrastructure/storage/compatibility_state.rb +6 -17
- data/lib/stoplight/infrastructure/system_clock.rb +16 -0
- data/lib/stoplight/notifier.rb +11 -0
- data/lib/stoplight/state.rb +9 -0
- data/lib/stoplight/types.rb +29 -0
- data/lib/stoplight/undefined.rb +16 -0
- data/lib/stoplight/version.rb +1 -1
- data/lib/stoplight/wiring/config_compatibility_validator.rb +54 -0
- data/lib/stoplight/wiring/configuration_dsl.rb +101 -0
- data/lib/stoplight/wiring/data_store_backend.rb +26 -0
- data/lib/stoplight/wiring/default.rb +1 -1
- data/lib/stoplight/wiring/default_config.rb +21 -0
- data/lib/stoplight/wiring/default_configuration.rb +70 -53
- data/lib/stoplight/wiring/light_builder.rb +76 -63
- data/lib/stoplight/wiring/light_factory/traffic_control_dsl.rb +3 -3
- data/lib/stoplight/wiring/light_factory/traffic_recovery_dsl.rb +4 -4
- data/lib/stoplight/wiring/light_factory.rb +78 -52
- data/lib/stoplight/wiring/memory/backend.rb +57 -0
- data/lib/stoplight/wiring/redis/backend.rb +116 -0
- data/lib/stoplight/wiring/storage_set.rb +12 -0
- data/lib/stoplight/wiring/storage_set_builder.rb +51 -0
- data/lib/stoplight/wiring/system/light_builder.rb +47 -0
- data/lib/stoplight/wiring/system/light_factory.rb +64 -0
- data/lib/stoplight/wiring/system.rb +129 -0
- data/lib/stoplight.rb +196 -25
- data/sig/_private/generators/stoplight/install/install_generator.rbs +22 -0
- data/sig/_private/stoplight/common/deprecations.rbs +9 -0
- data/sig/_private/stoplight/data_store.rbs +6 -0
- data/sig/_private/stoplight/domain/compatibility_result.rbs +18 -0
- data/sig/_private/stoplight/domain/config.rbs +65 -0
- data/sig/_private/stoplight/domain/error_tracking_policy.rbs +14 -0
- data/sig/_private/stoplight/domain/failure.rbs +16 -0
- data/sig/_private/stoplight/domain/light.rbs +25 -0
- data/sig/_private/stoplight/domain/light_info.rbs +19 -0
- data/sig/_private/stoplight/domain/metrics_snapshot.rbs +38 -0
- data/sig/_private/stoplight/domain/ports/clock.rbs +18 -0
- data/sig/_private/stoplight/domain/ports/data_store.rbs +76 -0
- data/{lib/stoplight/domain/light_factory.rb → sig/_private/stoplight/domain/ports/light_factory.rbs} +33 -28
- data/sig/_private/stoplight/domain/ports/metrics_store.rbs +29 -0
- data/sig/_private/stoplight/domain/ports/recovery_lock_store.rbs +52 -0
- data/sig/_private/stoplight/domain/ports/recovery_lock_token.rbs +6 -0
- data/sig/_private/stoplight/domain/ports/run_strategy.rbs +14 -0
- data/sig/_private/stoplight/domain/ports/state_store.rbs +79 -0
- data/sig/_private/stoplight/domain/ports/traffic_control.rbs +41 -0
- data/sig/_private/stoplight/domain/ports/traffic_recovery.rbs +47 -0
- data/sig/_private/stoplight/domain/state_snapshot.rbs +32 -0
- data/sig/_private/stoplight/domain/storage/recovery_lock_token.rbs +11 -0
- data/sig/_private/stoplight/domain/strategies/green_run_strategy.rbs +17 -0
- data/sig/_private/stoplight/domain/strategies/red_run_strategy.rbs +17 -0
- data/sig/_private/stoplight/domain/strategies/yellow_run_strategy.rbs +42 -0
- data/{lib/stoplight/domain/tracker/base.rb → sig/_private/stoplight/domain/tracker/base.rbs} +0 -4
- data/sig/_private/stoplight/domain/tracker/recovery_probe.rbs +25 -0
- data/sig/_private/stoplight/domain/tracker/request.rbs +26 -0
- data/sig/_private/stoplight/domain/traffic_control/consecutive_errors.rbs +9 -0
- data/sig/_private/stoplight/domain/traffic_control/error_rate.rbs +13 -0
- data/sig/_private/stoplight/domain/traffic_recovery/consecutive_successes.rbs +9 -0
- data/sig/_private/stoplight/domain/traffic_recovery.rbs +9 -0
- data/sig/_private/stoplight/infrastructure/fail_safe/data_store.rbs +26 -0
- data/sig/_private/stoplight/infrastructure/fail_safe/storage/metrics.rbs +25 -0
- data/sig/_private/stoplight/infrastructure/fail_safe/storage/recovery_lock.rbs +29 -0
- data/sig/_private/stoplight/infrastructure/fail_safe/storage/recovery_lock_token.rbs +19 -0
- data/sig/_private/stoplight/infrastructure/fail_safe/storage/state.rbs +25 -0
- data/sig/_private/stoplight/infrastructure/memory/data_store/metrics.rbs +25 -0
- data/sig/_private/stoplight/infrastructure/memory/data_store/recovery_lock_store.rbs +19 -0
- data/sig/_private/stoplight/infrastructure/memory/data_store/recovery_lock_token.rbs +17 -0
- data/sig/_private/stoplight/infrastructure/memory/data_store/sliding_window.rbs +27 -0
- data/sig/_private/stoplight/infrastructure/memory/data_store/state.rbs +17 -0
- data/sig/_private/stoplight/infrastructure/memory/data_store.rbs +30 -0
- data/sig/_private/stoplight/infrastructure/memory/storage/recovery_lock.rbs +15 -0
- data/sig/_private/stoplight/infrastructure/memory/storage/recovery_metrics.rbs +10 -0
- data/sig/_private/stoplight/infrastructure/memory/storage/state.rbs +28 -0
- data/sig/_private/stoplight/infrastructure/memory/storage/unbounded_metrics.rbs +25 -0
- data/sig/_private/stoplight/infrastructure/memory/storage/window_metrics.rbs +26 -0
- data/sig/_private/stoplight/infrastructure/notifier/fail_safe.rbs +17 -0
- data/sig/_private/stoplight/infrastructure/notifier/generic.rbs +18 -0
- data/sig/_private/stoplight/infrastructure/notifier/io.rbs +14 -0
- data/sig/_private/stoplight/infrastructure/notifier/logger.rbs +14 -0
- data/sig/_private/stoplight/infrastructure/redis/data_store/recovery_lock_store.rbs +24 -0
- data/sig/_private/stoplight/infrastructure/redis/data_store/recovery_lock_token.rbs +21 -0
- data/sig/_private/stoplight/infrastructure/redis/data_store/scripting.rbs +34 -0
- data/sig/_private/stoplight/infrastructure/redis/data_store.rbs +67 -0
- data/sig/_private/stoplight/infrastructure/redis/storage/key_space.rbs +19 -0
- data/sig/_private/stoplight/infrastructure/redis/storage/metrics.rbs +17 -0
- data/sig/_private/stoplight/infrastructure/redis/storage/recovery_lock.rbs +26 -0
- data/sig/_private/stoplight/infrastructure/redis/storage/recovery_metrics.rbs +10 -0
- data/sig/_private/stoplight/infrastructure/redis/storage/scripting.rbs +13 -0
- data/sig/_private/stoplight/infrastructure/redis/storage/state.rbs +32 -0
- data/sig/_private/stoplight/infrastructure/redis/storage/unbounded_metrics.rbs +21 -0
- data/sig/_private/stoplight/infrastructure/redis/storage/window_metrics.rbs +34 -0
- data/sig/_private/stoplight/infrastructure/storage/compatibility_metrics.rbs +17 -0
- data/sig/_private/stoplight/infrastructure/storage/compatibility_recovery_lock.rbs +13 -0
- data/sig/_private/stoplight/infrastructure/storage/compatibility_recovery_metrics.rbs +14 -0
- data/sig/_private/stoplight/infrastructure/storage/compatibility_state.rbs +14 -0
- data/sig/_private/stoplight/infrastructure/system_clock.rbs +7 -0
- data/sig/_private/stoplight/system/light_builder.rbs +23 -0
- data/sig/_private/stoplight/system/light_factory.rbs +17 -0
- data/sig/_private/stoplight/types.rbs +6 -0
- data/sig/_private/stoplight/wiring/config_compatibility_validator.rbs +19 -0
- data/sig/_private/stoplight/wiring/configuration_dsl.rbs +43 -0
- data/sig/_private/stoplight/wiring/data_store_backend.rbs +11 -0
- data/sig/_private/stoplight/wiring/default.rbs +26 -0
- data/{lib/stoplight/wiring/data_store/memory.rb → sig/_private/stoplight/wiring/default_config.rbs} +1 -4
- data/sig/_private/stoplight/wiring/default_configuration.rbs +29 -0
- data/sig/_private/stoplight/wiring/light_builder.rbs +48 -0
- data/sig/_private/stoplight/wiring/light_factory/traffic_control_dsl.rbs +7 -0
- data/sig/_private/stoplight/wiring/light_factory/traffic_recovery_dsl.rbs +7 -0
- data/sig/_private/stoplight/wiring/light_factory.rbs +16 -0
- data/sig/_private/stoplight/wiring/memory/backend.rbs +26 -0
- data/sig/_private/stoplight/wiring/notifier_factory.rbs +10 -0
- data/sig/_private/stoplight/wiring/redis/backend.rbs +38 -0
- data/sig/_private/stoplight/wiring/storage_set.rbs +38 -0
- data/sig/_private/stoplight/wiring/storage_set_builder.rbs +15 -0
- data/sig/_private/stoplight/wiring/system.rbs +15 -0
- data/sig/_private/stoplight.rbs +48 -0
- data/sig/stoplight/color.rbs +7 -0
- data/sig/stoplight/data_store.rbs +19 -0
- data/sig/stoplight/error.rbs +20 -0
- data/sig/stoplight/notifier.rbs +11 -0
- data/sig/stoplight/ports/configuration.rbs +19 -0
- data/sig/stoplight/ports/exception_matcher.rbs +8 -0
- data/sig/stoplight/ports/light.rbs +12 -0
- data/sig/stoplight/ports/light_info.rbs +5 -0
- data/sig/stoplight/ports/state_transition_notifier.rbs +15 -0
- data/sig/stoplight/ports/system.rbs +21 -0
- data/sig/stoplight/state.rbs +7 -0
- data/sig/stoplight/undefined.rbs +9 -0
- data/sig/stoplight/version.rbs +3 -0
- data/sig/stoplight.rbs +66 -0
- metadata +175 -47
- data/lib/stoplight/domain/color.rb +0 -11
- data/lib/stoplight/domain/data_store.rb +0 -146
- data/lib/stoplight/domain/error.rb +0 -42
- data/lib/stoplight/domain/metrics.rb +0 -64
- data/lib/stoplight/domain/recovery_lock_token.rb +0 -15
- data/lib/stoplight/domain/state.rb +0 -11
- data/lib/stoplight/domain/state_transition_notifier.rb +0 -25
- data/lib/stoplight/domain/storage/metrics.rb +0 -42
- data/lib/stoplight/domain/storage/recovery_lock.rb +0 -56
- data/lib/stoplight/domain/storage/state.rb +0 -87
- data/lib/stoplight/domain/strategies/run_strategy.rb +0 -22
- data/lib/stoplight/domain/traffic_control/base.rb +0 -74
- data/lib/stoplight/domain/traffic_recovery/base.rb +0 -79
- data/lib/stoplight/wiring/data_store/base.rb +0 -11
- data/lib/stoplight/wiring/data_store/redis.rb +0 -25
- data/lib/stoplight/wiring/default_factory_builder.rb +0 -25
- data/lib/stoplight/wiring/light/default_config.rb +0 -18
- data/lib/stoplight/wiring/light/system_config.rb +0 -11
- data/lib/stoplight/wiring/light_factory/compatibility_validator.rb +0 -55
- data/lib/stoplight/wiring/light_factory/config_normalizer.rb +0 -71
- data/lib/stoplight/wiring/light_factory/configuration_pipeline.rb +0 -72
- data/lib/stoplight/wiring/public_api.rb +0 -29
- /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/get_metrics.lua +0 -0
- /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/record_failure.lua +0 -0
- /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/record_recovery_probe_failure.lua +0 -0
- /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/record_recovery_probe_success.lua +0 -0
- /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/record_success.lua +0 -0
- /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/release_lock.lua +0 -0
- /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/transition_to_green.lua +0 -0
- /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/transition_to_red.lua +0 -0
- /data/lib/stoplight/infrastructure/{data_store/redis → redis/data_store}/lua_scripts/transition_to_yellow.lua +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 186bd97d97bfe0d58398e0f7516ee2679567e8a124395291f63a91902d493ece
|
|
4
|
+
data.tar.gz: 59b9e3fdac592528d0c0cba71c8e5da88481bffe670e0c0129c41910264ca8a3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2c9f21452070dbade7a8320b1f5344ce1610ea6b2254d15f2a709a7b3cbad045f7865f12b2fd4afeb2882c3b8fabc405666b21ef17222e20733bc9c7bbb60802
|
|
7
|
+
data.tar.gz: c5a77e5313cdabfbe47fa536b54df0774a0899962eaf8b6e3a239d1498f50b3724018859ec2c3beb282fbe29731862356ddd41254bcd8f119a1e9ffe07f55344
|
data/README.md
CHANGED
|
@@ -648,7 +648,7 @@ Fowler’s [CircuitBreaker][] article.
|
|
|
648
648
|
[the change log]: CHANGELOG.md
|
|
649
649
|
[stoplight-sentry]: https://github.com/bolshakov/stoplight-sentry
|
|
650
650
|
[stoplight-honeybadger]: https://github.com/qoqa/stoplight-honeybadger
|
|
651
|
-
[notifier interface documentation]: https://github.com/bolshakov/stoplight/blob/main/lib/stoplight/
|
|
651
|
+
[notifier interface documentation]: https://github.com/bolshakov/stoplight/blob/main/lib/stoplight/domain/state_transition_notifier.rb
|
|
652
652
|
[camdez]: https://github.com/camdez
|
|
653
653
|
[tfausak]: https://github.com/tfausak
|
|
654
654
|
[bolshakov]: https://github.com/bolshakov
|
data/UPGRADING.md
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
## Stoplight 5.0
|
|
2
|
+
|
|
3
|
+
Stoplight 5.0 introduces several breaking changes, so you'll need to set aside some time to update your code. The good
|
|
4
|
+
news is that most of the changes are pretty straightforward, and once you're done, you'll have a much cleaner and
|
|
5
|
+
more powerful setup.
|
|
6
|
+
|
|
7
|
+
Here's what you'll want to tackle during your upgrade. Don't worry if this looks like a lot - most of these are simple
|
|
8
|
+
find-and-replace operations:
|
|
9
|
+
|
|
10
|
+
- [] Update global configuration to use the new block syntax
|
|
11
|
+
- [] Replace any remaining `Stoplight() {}` calls with `Stoplight().run {}`
|
|
12
|
+
- [] Convert error handlers to tracked/skipped error lists
|
|
13
|
+
- [] Move fallbacks from configuration to `#run` method calls
|
|
14
|
+
- [] Account for Stoplight state reset after deployment
|
|
15
|
+
- [] Test thoroughly in a staging environment
|
|
16
|
+
|
|
17
|
+
### Global Configuration Redesign
|
|
18
|
+
|
|
19
|
+
The biggest change you'll see is how global configuration works. We've moved away from individual setter methods to a
|
|
20
|
+
unified configuration block. The old individual setters were causing race conditions in production - imagine
|
|
21
|
+
one part of your app setting the data store while another part was setting notifiers, and depending on timing, you could
|
|
22
|
+
end up with inconsistent configuration states. The new block-based approach ensures all your settings are applied
|
|
23
|
+
atomically, which eliminates these edge cases completely.
|
|
24
|
+
|
|
25
|
+
If you have code that looks like this:
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
# Old way that won't work anymore
|
|
29
|
+
Stoplight.default_data_store = Stoplight::DataStore::Redis.new(redis)
|
|
30
|
+
Stoplight.default_notifiers += [Stoplight::Notifier::Logger.new(Rails.logger)]
|
|
31
|
+
Stoplight.default_error_notifier = ->(error) { Bugsnag.notify(error) }
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
You'll need to convert it to the new block syntax:
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
# New way that's much more reliable
|
|
38
|
+
Stoplight.configure do |config|
|
|
39
|
+
config.data_store = Stoplight::DataStore::Redis.new(redis)
|
|
40
|
+
config.notifiers += [Stoplight::Notifier::Logger.new(Rails.logger)]
|
|
41
|
+
config.error_notifier = ->(error) { Bugsnag.notify(error) }
|
|
42
|
+
end
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The new approach ensures all your configuration is applied atomically, which prevents some weird edge cases where
|
|
46
|
+
partial configuration changes could cause unexpected behavior.
|
|
47
|
+
|
|
48
|
+
### Cleaning Up Old Deprecated Code
|
|
49
|
+
|
|
50
|
+
Remember `Stoplight() {}` interface that got deprecated way back in 4.0? Well, it's finally gone completely. If you
|
|
51
|
+
still have any of these in your codebase, you'll need to convert them to use the run method:
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
# This won't work anymore
|
|
55
|
+
Stoplight('API Call') { make_api_request }.run
|
|
56
|
+
|
|
57
|
+
# Change it to this
|
|
58
|
+
Stoplight('API Call').run { make_api_request }
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Most codebases shouldn't have these anymore since they've been deprecated for a while, but it's worth doing a quick
|
|
62
|
+
grep to make sure.
|
|
63
|
+
|
|
64
|
+
### Error Handling Gets Much Simpler
|
|
65
|
+
|
|
66
|
+
This is probably the change you'll appreciate most once you're used to it. The old `with_error_handler` callback system
|
|
67
|
+
was confusing and led to a lot of boilerplate code, but more importantly, it was a source of bugs. We kept
|
|
68
|
+
seeing cases where developers would forget to call the handler properly, or accidentally raise errors when they meant
|
|
69
|
+
to track them, or create configuration that leaked between different circuit breakers. The new approach is much more
|
|
70
|
+
straightforward and eliminates these problems entirely - you just tell Stoplight which errors to track and which to ignore.
|
|
71
|
+
|
|
72
|
+
If you have complex error handler logic like this:
|
|
73
|
+
|
|
74
|
+
```ruby
|
|
75
|
+
# Old complicated way
|
|
76
|
+
light = Stoplight('api-call')
|
|
77
|
+
.with_error_handler do |error, handle|
|
|
78
|
+
if error.is_a?(ActiveRecord::RecordNotFound) || error.is_a?(ActiveRecord::RecordInvalid)
|
|
79
|
+
raise error # Don't track this error
|
|
80
|
+
else
|
|
81
|
+
handle.call(error) # Track this error
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
You can replace it with this much cleaner approach:
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
# New simple way
|
|
90
|
+
light = Stoplight('api-call', skipped_errors: [ActiveRecord::RecordNotFound, ActiveRecord::RecordInvalid])
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The new system is way more explicit about what's happening, and you don't have to worry about accidentally forgetting
|
|
94
|
+
to call the handler or raising the error in the right places.
|
|
95
|
+
|
|
96
|
+
### Fallbacks Work Differently Now
|
|
97
|
+
|
|
98
|
+
Fallbacks have moved from being configured on the light instance to being passed directly to the run method. This might
|
|
99
|
+
seem like a small change, but it's actually pretty powerful and solves a real problem we've observed in production
|
|
100
|
+
codebases. When fallbacks were configured on the light instance, you'd often end up with the same circuit breaker
|
|
101
|
+
protecting multiple different operations, but each operation would need its own fallback strategy. This led to either
|
|
102
|
+
duplicated light configurations or inappropriate fallbacks being applied to the wrong operations. The new approach
|
|
103
|
+
makes each operation's fallback explicit and prevents configuration contamination between different use cases.
|
|
104
|
+
|
|
105
|
+
Instead of configuring fallbacks upfront like this:
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
# Old way
|
|
109
|
+
light = Stoplight("Payment Gateway")
|
|
110
|
+
.with_fallback { |error| handle_payment_failure(error) }
|
|
111
|
+
result = light.run { process_payment }
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
You now pass the fallback directly to the run method:
|
|
115
|
+
|
|
116
|
+
```ruby
|
|
117
|
+
# New way
|
|
118
|
+
light = Stoplight('Payment Gateway')
|
|
119
|
+
result = light.run(->(error) { handle_payment_failure(error) }) { process_payment }
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
This makes it much clearer which fallback belongs to which operation, and you can easily have the same circuit breaker
|
|
123
|
+
protect multiple operations with completely different fallback behaviors.
|
|
124
|
+
|
|
125
|
+
### Redis Data Gets a Fresh Start
|
|
126
|
+
|
|
127
|
+
Here's the one change that doesn't require any code updates but is worth knowing about: Stoplight 5.0 uses completely
|
|
128
|
+
new Redis data structures that aren't compatible with the old version. We didn't make this change lightly - the old
|
|
129
|
+
data structures were becoming a bottleneck for the new features we wanted to build, especially around better
|
|
130
|
+
distributed coordination and more sophisticated error tracking. The new structures use Lua scripting for atomic
|
|
131
|
+
operations, which eliminates race conditions in distributed environments and provides much better performance.
|
|
132
|
+
Unfortunately, there was no practical way to migrate the old data format without significant complexity and potential
|
|
133
|
+
data corruption risks, so we opted for a clean break.
|
|
134
|
+
|
|
135
|
+
For most applications, this isn't a big deal since circuit breakers are designed to adapt quickly to current conditions
|
|
136
|
+
anyway. But if you have circuit breakers that take a long time to fail and you're upgrading during a period when your
|
|
137
|
+
dependencies are already having issues, you might want to plan your deployment timing accordingly.
|
|
138
|
+
|
|
139
|
+
The old Redis data won't be deleted, so if you really need to reference historical information for debugging purposes,
|
|
140
|
+
it'll still be there. But Stoplight will ignore it completely and start fresh.
|
|
141
|
+
|
|
142
|
+
### Testing Your Migration
|
|
143
|
+
|
|
144
|
+
Once you've made all these changes, definitely test everything thoroughly in a staging environment that mirrors your
|
|
145
|
+
production setup. Pay special attention to how your circuit breakers behave under load and make sure your error
|
|
146
|
+
classification is working the way you expect.
|
|
147
|
+
|
|
148
|
+
The new error handling system is much more explicit, but that also means if you get the configuration wrong, it'll be
|
|
149
|
+
more obvious what's happening (which is actually a good thing).
|
|
150
|
+
|
|
151
|
+
### Getting Help
|
|
152
|
+
|
|
153
|
+
If you run into any issues during the migration, don't hesitate to post a message to our [Discussions forum]. We've
|
|
154
|
+
tried to make the error messages as clear as possible when something's misconfigured. The new APIs are much more
|
|
155
|
+
consistent and predictable once you get used to them.
|
|
156
|
+
|
|
157
|
+
Overall, while this upgrade does require some work upfront, the end result is a much cleaner and more reliable circuit
|
|
158
|
+
breaker setup that should serve you well going forward.
|
|
159
|
+
|
|
160
|
+
## Stoplight 4.0
|
|
161
|
+
|
|
162
|
+
### Notifiers have dropped!
|
|
163
|
+
|
|
164
|
+
With this release, we've officially moved all third-party notifiers out of Stoplight.
|
|
165
|
+
The only notifiers that remain to be in the Stoplight distribution are:
|
|
166
|
+
|
|
167
|
+
* `Stoplight::Notifier::IO`
|
|
168
|
+
* `Stoplight::Notifier::Logger`
|
|
169
|
+
|
|
170
|
+
#### Why was this decision made?
|
|
171
|
+
|
|
172
|
+
We've taken this decision for the following technical reasons:
|
|
173
|
+
|
|
174
|
+
* We wanted to free the maintainers from supporting all the different notifiers, relying more on
|
|
175
|
+
the community to maintain them based on broad interest.
|
|
176
|
+
* Moving notifiers into separate gems allow to solve the dependency issues once and for all.
|
|
177
|
+
The notifiers gems will be able to automatically pull any necessary dependency, without having to
|
|
178
|
+
rely on the developer to do so.
|
|
179
|
+
* With the community-supported notifiers, we can solve the third-party services compatibility issue. Such services
|
|
180
|
+
arise and go and Stoplight should not depend on their lifecycle.
|
|
181
|
+
|
|
182
|
+
#### So, what does this mean for me?
|
|
183
|
+
|
|
184
|
+
Unfortunately, we cannot support all the possible notifiers.
|
|
185
|
+
|
|
186
|
+
* All the notifiers relying on third-party services have been dropped.
|
|
187
|
+
* We implemented the Sentry notifier as an external [stoplight-sentry] gem. You can use it as a reference implementation.
|
|
188
|
+
* We added a [Community-supported notifiers] section and encourage you to contribute by adding your notifiers.
|
|
189
|
+
|
|
190
|
+
#### All right! What should I change in my code immediately after upgrading?
|
|
191
|
+
|
|
192
|
+
* If you just use the default, `Stoplight::Notifier::IO`, or `Stoplight::Notifier::Logger` notifiers, then you
|
|
193
|
+
don't need to do anything!
|
|
194
|
+
* Otherwise, you many need to find a third-party notifier:
|
|
195
|
+
|
|
196
|
+
```ruby
|
|
197
|
+
# Gemfile
|
|
198
|
+
gem 'sentry'
|
|
199
|
+
gem 'stoplight'
|
|
200
|
+
gem 'stoplight-sentry'
|
|
201
|
+
|
|
202
|
+
# Code
|
|
203
|
+
Stoplight.default_notifiers += [Stoplight::Sentry::Notifier.new(Sentry)]
|
|
204
|
+
```
|
|
205
|
+
* If you cannot find a notifier gem, you may need to implement your own. Consider checking the
|
|
206
|
+
[How to implement your own notifier?] guide which contains all the information needed to implement a notifier. You
|
|
207
|
+
can use [dropped notifiers] for the inspiration.
|
|
208
|
+
|
|
209
|
+
### Stoplight() interface has changed
|
|
210
|
+
|
|
211
|
+
We moved block argument from the `Stoplight()` function to the `#run` method.
|
|
212
|
+
|
|
213
|
+
#### Why was this decision made?
|
|
214
|
+
|
|
215
|
+
We aim to make Stoplight's configuration sharable across the code. Due to this change, it's possible to run
|
|
216
|
+
different code blocks with the same Stoplight configuration:
|
|
217
|
+
|
|
218
|
+
```ruby
|
|
219
|
+
light = Stoplight('http-api').with_cool_off_time(300)
|
|
220
|
+
light.run { call_this }
|
|
221
|
+
light.run { call_that }
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Another benefit is that now you can easily inspect the status of the circuit breaker [without passing an empty block]:
|
|
225
|
+
|
|
226
|
+
```ruby
|
|
227
|
+
light.color
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
#### So, what does this mean for me?
|
|
231
|
+
|
|
232
|
+
Stoplight 4.0 supports both an old and a new interface. However, the old interface is deprecated. To
|
|
233
|
+
update to Stoplight 5.0, you will need to switch to the new syntax.
|
|
234
|
+
|
|
235
|
+
```diff
|
|
236
|
+
- Stoplight('example') { 1 / 0 }.run
|
|
237
|
+
+ Stoplight('example').run { 1 / 0 }
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Stoplight::Light becomes private
|
|
241
|
+
|
|
242
|
+
This class has always considered private but some developers preferred to use `Stoplight::Light#new` instead of
|
|
243
|
+
`Stoplight()`. In the next major release the use of `Stoplight::Light#new` will be forbidden.
|
|
244
|
+
|
|
245
|
+
#### Why was this decision made?
|
|
246
|
+
|
|
247
|
+
We want to provide a simple, concise Stoplight interface. Having a single public interface guarantees users
|
|
248
|
+
use it the right way.
|
|
249
|
+
|
|
250
|
+
#### So, what does this mean for me?
|
|
251
|
+
|
|
252
|
+
Any use of `Stoplight::Light` outside of Stoplight itself is deprecated in Stoplight 4.0. To update to the
|
|
253
|
+
next major version (Stoplight 5.0), you will need to change a few things:
|
|
254
|
+
|
|
255
|
+
```diff
|
|
256
|
+
- Stoplight::Light.default_data_store = data_store
|
|
257
|
+
+ Stoplight.default_data_store = data_store
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
```diff
|
|
261
|
+
- Stoplight::Light.default_notifiers += [notifier]
|
|
262
|
+
+ Stoplight.default_notifiers += [notifier]
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
```diff
|
|
266
|
+
- Stoplight::Light.default_error_notifier = ->(*) {}
|
|
267
|
+
+ Stoplight.default_error_notifier = ->(*) {}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
In case you prefer to check types in your specs, you may need to switch it from checking for `Stoplight::Light` class
|
|
271
|
+
to `Stoplight::CircuitBreaker`. The `Stoplight::CircuitBreaker` abstract module considered the only public interface.
|
|
272
|
+
|
|
273
|
+
Under the hood, we use two slightly different implementations to provide a smooth transition to the new interface
|
|
274
|
+
and to make it possible to pass Stoplight as a dependency.
|
|
275
|
+
|
|
276
|
+
#### All right! What should I change in my code immediately after upgrading?
|
|
277
|
+
|
|
278
|
+
You might encounter a few deprecation warnings, but you do not need to changes anything in your code in this release.
|
|
279
|
+
|
|
280
|
+
### Change in Redis Data Structures
|
|
281
|
+
|
|
282
|
+
Redis Data store in Stoplight 4.0 uses a new data structure under the hood.
|
|
283
|
+
|
|
284
|
+
#### Why was this decision made?
|
|
285
|
+
|
|
286
|
+
This decision was made to enable the implementation of error counting using a [sliding window] approach. This feature
|
|
287
|
+
allows Stoplight to count only errors that have occurred recently.
|
|
288
|
+
|
|
289
|
+
#### So, what does this mean for me?
|
|
290
|
+
|
|
291
|
+
After upgrading to this version, Stoplight will not be aware of errors that occurred before the update.
|
|
292
|
+
|
|
293
|
+
#### All right! What should I change in my code immediately after upgrading?
|
|
294
|
+
|
|
295
|
+
Nothing. Stoplight will function as usual.
|
|
296
|
+
|
|
297
|
+
[stoplight-sentry]: https://github.com/bolshakov/stoplight-sentry
|
|
298
|
+
[Community-supported notifiers]: https://github.com/bolshakov/stoplight/tree/master#community-supported-notifiers
|
|
299
|
+
[How to implement your own notifier?]: https://github.com/bolshakov/stoplight/blob/master/lib/stoplight/notifier/generic.rb
|
|
300
|
+
[dropped notifiers]: https://github.com/bolshakov/stoplight/tree/v3.0.1/lib/stoplight/notifier
|
|
301
|
+
[without passing an empty block]: https://github.com/bolshakov/stoplight-admin/blob/9c9848eb94410e46b20972548f0863db224cb6da/lib/sinatra/stoplight_admin.rb#L30
|
|
302
|
+
[sliding window]: https://github.com/bolshakov/stoplight#custom-window-size
|
|
303
|
+
[Discussions forum]: https://github.com/bolshakov/stoplight/discussions/categories/q-a
|
|
@@ -11,7 +11,12 @@ end
|
|
|
11
11
|
module Stoplight
|
|
12
12
|
module Generators
|
|
13
13
|
class InstallGenerator < ::Rails::Generators::Base # :nodoc:
|
|
14
|
-
|
|
14
|
+
case (root = __dir__)
|
|
15
|
+
when String
|
|
16
|
+
source_root File.expand_path("templates", root)
|
|
17
|
+
else
|
|
18
|
+
raise "cannot find templates root"
|
|
19
|
+
end
|
|
15
20
|
|
|
16
21
|
class_option :with_admin_panel, type: :boolean, optional: true,
|
|
17
22
|
desc: "Define whether to set up admin panel"
|
|
@@ -14,16 +14,32 @@ module Stoplight
|
|
|
14
14
|
Dependencies.new(data_store:)
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
def time_ago_in_words(time)
|
|
18
|
+
time_difference = Time.now.utc - time
|
|
19
|
+
if time_difference < 1
|
|
20
|
+
"just now"
|
|
21
|
+
elsif time_difference < 60
|
|
22
|
+
"#{time_difference.to_i}s ago"
|
|
23
|
+
elsif time_difference < 3600
|
|
24
|
+
"#{(time_difference / 60).to_i}m ago"
|
|
25
|
+
elsif time_difference < 86400
|
|
26
|
+
"#{(time_difference / 3600).to_i}h ago"
|
|
27
|
+
else
|
|
28
|
+
"#{(time_difference / 86400).to_i}d ago"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
17
32
|
private def data_store
|
|
18
33
|
if settings.data_store.is_a?(Stoplight::DataStore::Memory)
|
|
19
34
|
raise "Stoplight Admin requires a persistent data store, but the current data store is Memory. " \
|
|
20
35
|
"Please configure a different data store in your Stoplight configuration."
|
|
21
36
|
else
|
|
22
37
|
Stoplight::Wiring::LightBuilder.new(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
38
|
+
config: Wiring::DefaultConfig.with(
|
|
39
|
+
name: "noname",
|
|
40
|
+
data_store: settings.data_store
|
|
41
|
+
),
|
|
42
|
+
factory: nil
|
|
27
43
|
).__send__(:data_store)
|
|
28
44
|
end
|
|
29
45
|
end
|
|
@@ -32,16 +32,22 @@ module Stoplight
|
|
|
32
32
|
# @return [<Stoplight::Failure>]
|
|
33
33
|
attr_reader :failures
|
|
34
34
|
|
|
35
|
+
# @!attribute failure_count
|
|
36
|
+
# @return [Integer]
|
|
37
|
+
attr_reader :failure_count
|
|
38
|
+
|
|
35
39
|
# @param name [String]
|
|
36
40
|
# @param color [String]
|
|
37
41
|
# @param state [String]
|
|
38
42
|
# @param failures [<Stoplight::Failure>]
|
|
39
|
-
|
|
43
|
+
# @param failure_count [Integer, nil]
|
|
44
|
+
def initialize(name:, color:, state:, failures:, failure_count: nil)
|
|
40
45
|
@id = SecureRandom.uuid
|
|
41
46
|
@name = name
|
|
42
47
|
@color = color
|
|
43
48
|
@state = state
|
|
44
49
|
@failures = failures
|
|
50
|
+
@failure_count = failure_count
|
|
45
51
|
end
|
|
46
52
|
|
|
47
53
|
def latest_failure
|
|
@@ -73,20 +79,24 @@ module Stoplight
|
|
|
73
79
|
[-COLORS.index(color), name]
|
|
74
80
|
end
|
|
75
81
|
|
|
82
|
+
def last_check = latest_failure&.time # TODO: take into account positive checks as well
|
|
83
|
+
|
|
76
84
|
# @return [String, nil]
|
|
77
85
|
def last_check_in_words
|
|
78
86
|
last_error_time = latest_failure&.time
|
|
79
87
|
return unless last_error_time
|
|
80
88
|
|
|
81
|
-
time_difference = Time.now - last_error_time
|
|
89
|
+
time_difference = Time.now.utc - last_error_time
|
|
82
90
|
if time_difference < 1
|
|
83
91
|
"just now"
|
|
84
92
|
elsif time_difference < 60
|
|
85
93
|
"#{time_difference.to_i}s ago"
|
|
86
94
|
elsif time_difference < 3600
|
|
87
95
|
"#{(time_difference / 60).to_i}m ago"
|
|
88
|
-
|
|
96
|
+
elsif time_difference < 86400
|
|
89
97
|
"#{(time_difference / 3600).to_i}h ago"
|
|
98
|
+
else
|
|
99
|
+
"#{(time_difference / 86400).to_i}d ago"
|
|
90
100
|
end
|
|
91
101
|
end
|
|
92
102
|
|
|
@@ -114,13 +124,19 @@ module Stoplight
|
|
|
114
124
|
def description_message
|
|
115
125
|
case color
|
|
116
126
|
when RED
|
|
117
|
-
if
|
|
127
|
+
if latest_failure
|
|
128
|
+
"#{latest_failure.error_class}: #{latest_failure.error_message}"
|
|
129
|
+
elsif locked?
|
|
118
130
|
"Circuit manually locked open"
|
|
119
131
|
else
|
|
120
|
-
"
|
|
132
|
+
"Not available"
|
|
121
133
|
end
|
|
122
134
|
when Stoplight::Color::YELLOW
|
|
123
|
-
|
|
135
|
+
if latest_failure
|
|
136
|
+
"#{latest_failure.error_class}: #{latest_failure.error_message}"
|
|
137
|
+
else
|
|
138
|
+
"Not available"
|
|
139
|
+
end
|
|
124
140
|
when GREEN
|
|
125
141
|
if locked?
|
|
126
142
|
"Circuit manually locked closed"
|
|
@@ -4,11 +4,11 @@ module Stoplight
|
|
|
4
4
|
class Admin
|
|
5
5
|
class LightsRepository
|
|
6
6
|
# @!attribute data_store
|
|
7
|
-
# @return [Stoplight::Domain::
|
|
7
|
+
# @return [Stoplight::Domain::_DataStore]
|
|
8
8
|
attr_reader :data_store
|
|
9
9
|
private :data_store
|
|
10
10
|
|
|
11
|
-
# @param data_store [Stoplight::Domain::
|
|
11
|
+
# @param data_store [Stoplight::Domain::_DataStore]
|
|
12
12
|
def initialize(data_store:)
|
|
13
13
|
@data_store = data_store
|
|
14
14
|
end
|
|
@@ -52,7 +52,7 @@ module Stoplight
|
|
|
52
52
|
# @return [void]
|
|
53
53
|
def unlock(name)
|
|
54
54
|
config = build_config(name)
|
|
55
|
-
data_store.set_state(config,
|
|
55
|
+
data_store.set_state(config, State::UNLOCKED)
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
# @param name [String] removes light metadata by its name
|
|
@@ -74,12 +74,13 @@ module Stoplight
|
|
|
74
74
|
name: name,
|
|
75
75
|
color: state_snapshot.color,
|
|
76
76
|
state: state_snapshot.locked_state,
|
|
77
|
-
failures: [metrics.last_error].compact
|
|
77
|
+
failures: [metrics.last_error].compact,
|
|
78
|
+
failure_count: metrics.consecutive_errors
|
|
78
79
|
)
|
|
79
80
|
end
|
|
80
81
|
|
|
81
82
|
private def build_config(name)
|
|
82
|
-
Wiring::
|
|
83
|
+
Wiring::DefaultConfig.with(name:)
|
|
83
84
|
end
|
|
84
85
|
end
|
|
85
86
|
end
|
|
@@ -107,8 +107,11 @@
|
|
|
107
107
|
<p><%= light.description_comment %></p>
|
|
108
108
|
</div>
|
|
109
109
|
<% if light.latest_failure %>
|
|
110
|
-
<div class="whitespace-nowrap">
|
|
111
|
-
<%=
|
|
110
|
+
<div class="whitespace-nowrap text-center">
|
|
111
|
+
<%= light.latest_failure.time.strftime("%F %T") %>
|
|
112
|
+
<span class="text-gray-400 dark:text-gray-500 uppercase tracking-wide">
|
|
113
|
+
UTC
|
|
114
|
+
</span>
|
|
112
115
|
</div>
|
|
113
116
|
<% end %>
|
|
114
117
|
</div>
|
|
@@ -117,13 +120,13 @@
|
|
|
117
120
|
<!-- Stats Row -->
|
|
118
121
|
<div class="flex justify-between text-xs text-gray-500 dark:text-gray-400 mt-3">
|
|
119
122
|
<div>
|
|
120
|
-
<span class="font-medium">Failures:</span> <%= light.
|
|
123
|
+
<span class="font-medium">Failures:</span> <%= light.failure_count %>
|
|
121
124
|
</div>
|
|
122
125
|
|
|
123
|
-
<% light.
|
|
126
|
+
<% light.last_check.then do |last_check| %>
|
|
124
127
|
<% if last_check %>
|
|
125
128
|
<div>
|
|
126
|
-
<span class="font-medium">Last Check:</span
|
|
129
|
+
<span class="font-medium">Last Check:</span><%= time_ago_in_words(last_check) %>
|
|
127
130
|
</div>
|
|
128
131
|
<% end %>
|
|
129
132
|
<% end %>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Stoplight
|
|
2
|
+
module DataStore
|
|
3
|
+
# @api private not for public use
|
|
4
|
+
class Base
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
class Redis < Base
|
|
8
|
+
# @!attribute redis
|
|
9
|
+
# @return [::Redis, ConnectionPool<::Redis>]
|
|
10
|
+
attr_reader :redis
|
|
11
|
+
|
|
12
|
+
# @!attribute warn_on_clock_skew
|
|
13
|
+
# @return [Boolean]
|
|
14
|
+
attr_reader :warn_on_clock_skew
|
|
15
|
+
|
|
16
|
+
# @param redis [::Redis, ConnectionPool<::Redis>]
|
|
17
|
+
# @param warn_on_clock_skew [Boolean] (true) Whether to warn about clock skew between Redis and
|
|
18
|
+
# the application server
|
|
19
|
+
def initialize(redis, warn_on_clock_skew: true)
|
|
20
|
+
@warn_on_clock_skew = warn_on_clock_skew
|
|
21
|
+
@redis = redis
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class Memory < Base
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -9,28 +9,28 @@ module Stoplight
|
|
|
9
9
|
class << self
|
|
10
10
|
# Creates a new +CompatibilityResult+ instance representing a compatible strategy.
|
|
11
11
|
#
|
|
12
|
-
# @return
|
|
12
|
+
# @return An instance with no errors.
|
|
13
13
|
def compatible
|
|
14
14
|
new(errors: [])
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
# Creates a new +CompatibilityResult+ instance representing an incompatible strategy.
|
|
18
18
|
#
|
|
19
|
-
# @param errors
|
|
20
|
-
# @return
|
|
19
|
+
# @param errors List of error messages indicating incompatibility.
|
|
20
|
+
# @return An instance with the provided errors.
|
|
21
21
|
def incompatible(*errors)
|
|
22
22
|
new(errors:)
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
# Initializes a new `CompatibilityResult` instance.
|
|
27
|
-
# @param errors
|
|
27
|
+
# @param errors List of error messages if the strategy is not compatible.
|
|
28
28
|
def initialize(errors: [])
|
|
29
29
|
@errors = errors.freeze
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
# Checks if the strategy is compatible.
|
|
33
|
-
# @return
|
|
33
|
+
# @return `true` if there are no errors, `false` otherwise.
|
|
34
34
|
def compatible?
|
|
35
35
|
@errors.empty?
|
|
36
36
|
end
|
|
@@ -38,11 +38,11 @@ module Stoplight
|
|
|
38
38
|
def incompatible? = !compatible?
|
|
39
39
|
|
|
40
40
|
# Retrieves the list of error messages.
|
|
41
|
-
# @return
|
|
41
|
+
# @return The list of error messages.
|
|
42
42
|
attr_reader :errors
|
|
43
43
|
|
|
44
44
|
# Retrieves a concatenated error message string.
|
|
45
|
-
# @return
|
|
45
|
+
# @return A string containing all error messages joined by "; ",
|
|
46
46
|
# or `nil` if the strategy is compatible.
|
|
47
47
|
def error_messages
|
|
48
48
|
unless compatible?
|