stoplight 0.4.1 → 0.5.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/CHANGELOG.md +15 -0
- data/LICENSE.md +1 -1
- data/README.md +66 -63
- data/lib/stoplight.rb +10 -15
- data/lib/stoplight/color.rb +9 -0
- data/lib/stoplight/data_store.rb +0 -146
- data/lib/stoplight/data_store/base.rb +7 -130
- data/lib/stoplight/data_store/memory.rb +25 -100
- data/lib/stoplight/data_store/redis.rb +61 -119
- data/lib/stoplight/default.rb +34 -0
- data/lib/stoplight/error.rb +0 -42
- data/lib/stoplight/failure.rb +21 -25
- data/lib/stoplight/light.rb +42 -127
- data/lib/stoplight/light/runnable.rb +97 -0
- data/lib/stoplight/notifier/base.rb +1 -4
- data/lib/stoplight/notifier/hip_chat.rb +17 -32
- data/lib/stoplight/notifier/io.rb +9 -9
- data/lib/stoplight/state.rb +9 -0
- data/spec/spec_helper.rb +2 -3
- data/spec/stoplight/color_spec.rb +39 -0
- data/spec/stoplight/data_store/base_spec.rb +56 -36
- data/spec/stoplight/data_store/memory_spec.rb +120 -2
- data/spec/stoplight/data_store/redis_spec.rb +123 -24
- data/spec/stoplight/data_store_spec.rb +2 -69
- data/spec/stoplight/default_spec.rb +86 -0
- data/spec/stoplight/error_spec.rb +29 -0
- data/spec/stoplight/failure_spec.rb +61 -51
- data/spec/stoplight/light/runnable_spec.rb +234 -0
- data/spec/stoplight/light_spec.rb +143 -191
- data/spec/stoplight/notifier/base_spec.rb +8 -11
- data/spec/stoplight/notifier/hip_chat_spec.rb +66 -55
- data/spec/stoplight/notifier/io_spec.rb +49 -21
- data/spec/stoplight/notifier_spec.rb +3 -0
- data/spec/stoplight/state_spec.rb +39 -0
- data/spec/stoplight_spec.rb +2 -65
- metadata +55 -19
- data/spec/support/data_store.rb +0 -36
- data/spec/support/fakeredis.rb +0 -3
- data/spec/support/hipchat.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ad268d747b85be7b3a0d773d9aeec70b1b22c25a
|
4
|
+
data.tar.gz: 56c5c8f88361a3c9d705212d9725251017097ddb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 043418c2e767031b2a229ad2e22d378c52101d342cdec3bb600bec88c5c46238c345eadb558d779ccedb8f60122b81b5cddf969dfb7dbf475e7bfe3e0cb7b3c2
|
7
|
+
data.tar.gz: 8a9952d663eb04f03e05736f3541ac09b69e69776c80265116d43a7c4c4e2e8d699691598ef8ae35d1c0018b5bc7880f73614894d79e194987961e857c2f7016
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
This project uses [Semantic Versioning][1].
|
4
|
+
|
5
|
+
- Data stores and notifiers can be configured on a per-stoplight basis. This
|
6
|
+
allows stoplights to use stoplights internally.
|
7
|
+
- Stoplights use stoplights internally to wrap calls to data stores and
|
8
|
+
notifiers. This means they gracefully handle either going down.
|
9
|
+
- Data stores only store failures and states. Also failures are stored in a ring
|
10
|
+
buffer. This drastically reduces the amount of data stored.
|
11
|
+
- Stoplights will use the fallback (if it's given) when they fail while they're
|
12
|
+
green. This means they won't re-raise exceptions if you provide a fallback.
|
13
|
+
- Stoplights pass the error to their notifiers when transitioning from green to
|
14
|
+
red.
|
15
|
+
|
3
16
|
## v0.4.1 (2014-10-03)
|
4
17
|
|
5
18
|
- Fixed a bug that caused green to red notifications to sometimes not be sent.
|
@@ -62,3 +75,5 @@
|
|
62
75
|
## v0.1.0 (2014-08-12)
|
63
76
|
|
64
77
|
- Initial release.
|
78
|
+
|
79
|
+
[1]: http://semver.org/spec/v2.0.0.html
|
data/LICENSE.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2014 Cameron Desautels &
|
1
|
+
Copyright (c) 2014 Cameron Desautels, Taylor Fausak & Justin Steffy
|
2
2
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
4
|
this software and associated documentation files (the "Software"), to deal in
|
data/README.md
CHANGED
@@ -33,7 +33,7 @@ Check out [stoplight-admin][12] for controlling your stoplights.
|
|
33
33
|
Add it to your Gemfile:
|
34
34
|
|
35
35
|
``` rb
|
36
|
-
gem 'stoplight', '~> 0.
|
36
|
+
gem 'stoplight', '~> 0.5.0'
|
37
37
|
```
|
38
38
|
|
39
39
|
Or install it manually:
|
@@ -42,8 +42,6 @@ Or install it manually:
|
|
42
42
|
$ gem install stoplight
|
43
43
|
```
|
44
44
|
|
45
|
-
This project uses [Semantic Versioning][13].
|
46
|
-
|
47
45
|
## Setup
|
48
46
|
|
49
47
|
### Data store
|
@@ -53,22 +51,22 @@ Stoplight uses an in-memory data store out of the box.
|
|
53
51
|
``` irb
|
54
52
|
>> require 'stoplight'
|
55
53
|
=> true
|
56
|
-
>> Stoplight.
|
54
|
+
>> Stoplight::Light.default_data_store
|
57
55
|
=> #<Stoplight::DataStore::Memory:...>
|
58
56
|
```
|
59
57
|
|
60
58
|
If you want to use a persistent data store, you'll have to set it up. Currently
|
61
59
|
the only supported persistent data store is Redis. Make sure you have [the Redis
|
62
|
-
gem][
|
60
|
+
gem][13] installed before configuring Stoplight.
|
63
61
|
|
64
62
|
``` irb
|
65
63
|
>> require 'redis'
|
66
64
|
=> true
|
67
|
-
>> redis = Redis.new
|
68
|
-
=> #<Redis
|
65
|
+
>> redis = Redis.new
|
66
|
+
=> #<Redis client ...>
|
69
67
|
>> data_store = Stoplight::DataStore::Redis.new(redis)
|
70
68
|
=> #<Stoplight::DataStore::Redis:...>
|
71
|
-
>> Stoplight.
|
69
|
+
>> Stoplight::Light.default_data_store = data_store
|
72
70
|
=> #<Stoplight::DataStore::Redis:...>
|
73
71
|
```
|
74
72
|
|
@@ -77,22 +75,22 @@ gem][14] installed before configuring Stoplight.
|
|
77
75
|
Stoplight sends notifications to standard error by default.
|
78
76
|
|
79
77
|
``` irb
|
80
|
-
>> Stoplight.
|
78
|
+
>> Stoplight::Light.default_notifiers
|
81
79
|
=> [#<Stoplight::Notifier::IO:...>]
|
82
80
|
```
|
83
81
|
|
84
82
|
If you want to send notifications elsewhere, you'll have to set them up.
|
85
83
|
Currently the only other supported notifier is HipChat. Make sure you have [the
|
86
|
-
HipChat gem][
|
84
|
+
HipChat gem][14] installed before configuring Stoplight.
|
87
85
|
|
88
86
|
``` irb
|
89
87
|
>> require 'hipchat'
|
90
88
|
=> true
|
91
|
-
>>
|
89
|
+
>> hip_chat = HipChat::Client.new('token')
|
92
90
|
=> #<HipChat::Client:...>
|
93
|
-
>> notifier = Stoplight::Notifier::HipChat.new(
|
91
|
+
>> notifier = Stoplight::Notifier::HipChat.new(hip_chat, 'room')
|
94
92
|
=> #<Stoplight::Notifier::HipChat:...>
|
95
|
-
>> Stoplight.
|
93
|
+
>> Stoplight::Light.default_notifiers += [notifier]
|
96
94
|
=> [#<Stoplight::Notifier::IO:...>, #<Stoplight::Notifier::HipChat:...>]
|
97
95
|
```
|
98
96
|
|
@@ -106,8 +104,8 @@ Stoplight:
|
|
106
104
|
``` rb
|
107
105
|
# config/initializers/stoplight.rb
|
108
106
|
require 'stoplight'
|
109
|
-
Stoplight.
|
110
|
-
Stoplight.
|
107
|
+
Stoplight::Light.default_data_store = Stoplight::DataStore::Redis.new(...)
|
108
|
+
Stoplight::Light.default_notifiers += [Stoplight::Notifier::HipChat.new(...)]
|
111
109
|
```
|
112
110
|
|
113
111
|
## Basic usage
|
@@ -125,8 +123,8 @@ the green state.
|
|
125
123
|
``` irb
|
126
124
|
>> light.run
|
127
125
|
=> 3.142857142857143
|
128
|
-
>> light.
|
129
|
-
=>
|
126
|
+
>> light.color
|
127
|
+
=> "green"
|
130
128
|
```
|
131
129
|
|
132
130
|
If everything goes well, you shouldn't even be able to tell that you're using a
|
@@ -147,12 +145,12 @@ ZeroDivisionError: divided by 0
|
|
147
145
|
>> light.run
|
148
146
|
ZeroDivisionError: divided by 0
|
149
147
|
>> light.run
|
148
|
+
Switching example-2 from green to red because ZeroDivisionError divided by 0
|
150
149
|
ZeroDivisionError: divided by 0
|
151
150
|
>> light.run
|
152
|
-
Switching example-2 from green to red.
|
153
151
|
Stoplight::Error::RedLight: example-2
|
154
|
-
>> light.
|
155
|
-
=>
|
152
|
+
>> light.color
|
153
|
+
=> "red"
|
156
154
|
```
|
157
155
|
|
158
156
|
When the stoplight changes from green to red, it will notify every configured
|
@@ -165,7 +163,7 @@ these are handled elsewhere in your stack and don't represent real failures. A
|
|
165
163
|
good example is `ActiveRecord::RecordNotFound`.
|
166
164
|
|
167
165
|
``` irb
|
168
|
-
>> light = Stoplight::Light.new('example-
|
166
|
+
>> light = Stoplight::Light.new('example-3') { User.find(123) }.
|
169
167
|
.. with_allowed_errors([ActiveRecord::RecordNotFound])
|
170
168
|
=> #<Stoplight::Light:...>
|
171
169
|
>> light.run
|
@@ -174,28 +172,34 @@ ActiveRecord::RecordNotFound: Couldn't find User with ID=123
|
|
174
172
|
ActiveRecord::RecordNotFound: Couldn't find User with ID=123
|
175
173
|
>> light.run
|
176
174
|
ActiveRecord::RecordNotFound: Couldn't find User with ID=123
|
177
|
-
>> light.
|
178
|
-
=>
|
175
|
+
>> light.color
|
176
|
+
=> "green"
|
179
177
|
```
|
180
178
|
|
181
179
|
### Custom fallback
|
182
180
|
|
183
|
-
|
184
|
-
|
185
|
-
|
181
|
+
By default, stoplights will re-raise errors when they're green. When they're
|
182
|
+
red, they'll raise a `Stoplight::Error::RedLight` error. You can provide a
|
183
|
+
fallback that will be called in both of these cases. It will be passed the error
|
184
|
+
if the light was green.
|
186
185
|
|
187
186
|
``` irb
|
188
|
-
>> light = Stoplight::Light.new('example-
|
189
|
-
.. with_fallback {
|
190
|
-
=> #<Stoplight::Light
|
187
|
+
>> light = Stoplight::Light.new('example-4') { 1 / 0 }.
|
188
|
+
.. with_fallback { |e| p e; 'default' }
|
189
|
+
=> #<Stoplight::Light:..>
|
191
190
|
>> light.run
|
192
|
-
|
191
|
+
#<ZeroDivisionError: divided by 0>
|
192
|
+
=> "default"
|
193
193
|
>> light.run
|
194
|
-
|
194
|
+
#<ZeroDivisionError: divided by 0>
|
195
|
+
=> "default"
|
195
196
|
>> light.run
|
196
|
-
|
197
|
+
Switching example-4 from green to red because ZeroDivisionError divided by 0
|
198
|
+
#<ZeroDivisionError: divided by 0>
|
199
|
+
=> "default"
|
197
200
|
>> light.run
|
198
|
-
|
201
|
+
nil
|
202
|
+
=> "default"
|
199
203
|
```
|
200
204
|
|
201
205
|
### Custom threshold
|
@@ -204,13 +208,14 @@ Some bits of code might be allowed to fail more or less frequently than others.
|
|
204
208
|
You can configure this by setting a custom threshold in seconds.
|
205
209
|
|
206
210
|
``` irb
|
207
|
-
>> light = Stoplight::Light.new('example-
|
211
|
+
>> light = Stoplight::Light.new('example-5') { fail }.
|
208
212
|
.. with_threshold(1)
|
209
213
|
=> #<Stoplight::Light:...>
|
210
214
|
>> light.run
|
215
|
+
Switching example-5 from green to red because RuntimeError
|
211
216
|
RuntimeError:
|
212
217
|
>> light.run
|
213
|
-
Stoplight::Error::RedLight: example-
|
218
|
+
Stoplight::Error::RedLight: example-5
|
214
219
|
```
|
215
220
|
|
216
221
|
### Custom timeout
|
@@ -220,7 +225,7 @@ A light in the red state for longer than the timeout will transition to the
|
|
220
225
|
yellow state. This timeout is customizable.
|
221
226
|
|
222
227
|
``` irb
|
223
|
-
>> light = Stoplight::Light.new('example-
|
228
|
+
>> light = Stoplight::Light.new('example-6') { fail }.
|
224
229
|
.. with_timeout(1)
|
225
230
|
=> #<Stoplight::Light:...>
|
226
231
|
>> light.run
|
@@ -228,14 +233,12 @@ RuntimeError:
|
|
228
233
|
>> light.run
|
229
234
|
RuntimeError:
|
230
235
|
>> light.run
|
236
|
+
Switching example-6 from green to red because RuntimeError
|
231
237
|
RuntimeError:
|
232
|
-
>> light.run
|
233
|
-
Switching example-7 from green to red.
|
234
|
-
Stoplight::Error::RedLight: example-7
|
235
238
|
>> sleep(1)
|
236
239
|
=> 1
|
237
|
-
>> light.
|
238
|
-
=>
|
240
|
+
>> light.color
|
241
|
+
=> "yellow"
|
239
242
|
>> light.run
|
240
243
|
RuntimeError:
|
241
244
|
```
|
@@ -254,7 +257,10 @@ class ApplicationController < ActionController::Base
|
|
254
257
|
def stoplight(&block)
|
255
258
|
Stoplight::Light.new("#{params[:controller]}##{params[:action]}", &block)
|
256
259
|
.with_allowed_errors([ActiveRecord::RecordNotFound])
|
257
|
-
.with_fallback
|
260
|
+
.with_fallback do |error|
|
261
|
+
Rails.logger.error(error)
|
262
|
+
render(nothing: true, status: :service_unavailable)
|
263
|
+
end
|
258
264
|
.run
|
259
265
|
end
|
260
266
|
end
|
@@ -269,16 +275,14 @@ override the default behavior. You can lock a light in either the green or red
|
|
269
275
|
state using `set_state`.
|
270
276
|
|
271
277
|
``` irb
|
272
|
-
>> light = Stoplight::Light.new('example-
|
273
|
-
=> #<Stoplight::Light
|
278
|
+
>> light = Stoplight::Light.new('example-7') { true }
|
279
|
+
=> #<Stoplight::Light:..>
|
274
280
|
>> light.run
|
275
281
|
=> true
|
276
|
-
>>
|
277
|
-
.. light.name, Stoplight::DataStore::STATE_LOCKED_RED)
|
282
|
+
>> light.data_store.set_state(light, Stoplight::State::LOCKED_RED)
|
278
283
|
=> "locked_red"
|
279
284
|
>> light.run
|
280
|
-
|
281
|
-
Stoplight::Error::RedLight: example-8
|
285
|
+
Stoplight::Error::RedLight: example-7
|
282
286
|
```
|
283
287
|
|
284
288
|
**Code in locked red lights may still run under certain conditions!** If you
|
@@ -288,13 +292,13 @@ locked state of any stoplights.
|
|
288
292
|
|
289
293
|
## Credits
|
290
294
|
|
291
|
-
Stoplight is brought to you by [@camdez][
|
292
|
-
[@OrgSync][
|
295
|
+
Stoplight is brought to you by [@camdez][15] and [@tfausak][16] from
|
296
|
+
[@OrgSync][17]. We were inspired by Martin Fowler's [CircuitBreaker][18]
|
293
297
|
article.
|
294
298
|
|
295
299
|
If this gem isn't cutting it for you, there are a few alternatives, including:
|
296
|
-
[circuit_b][
|
297
|
-
[ya_circuit_breaker][
|
300
|
+
[circuit_b][19], [circuit_breaker][20], [simple_circuit_breaker][21], and
|
301
|
+
[ya_circuit_breaker][22].
|
298
302
|
|
299
303
|
[1]: https://github.com/orgsync/stoplight
|
300
304
|
[2]: https://badge.fury.io/rb/stoplight.svg
|
@@ -308,14 +312,13 @@ If this gem isn't cutting it for you, there are a few alternatives, including:
|
|
308
312
|
[10]: https://gemnasium.com/orgsync/stoplight.svg
|
309
313
|
[11]: https://gemnasium.com/orgsync/stoplight
|
310
314
|
[12]: https://github.com/orgsync/stoplight-admin
|
311
|
-
[13]:
|
312
|
-
[14]: https://rubygems.org/gems/
|
313
|
-
[15]: https://
|
314
|
-
[16]: https://github.com/
|
315
|
-
[17]: https://github.com/
|
316
|
-
[18]:
|
317
|
-
[19]:
|
318
|
-
[20]: https://github.com/
|
319
|
-
[21]: https://github.com/
|
320
|
-
[22]: https://github.com/
|
321
|
-
[23]: https://github.com/wooga/circuit_breaker
|
315
|
+
[13]: https://rubygems.org/gems/redis
|
316
|
+
[14]: https://rubygems.org/gems/hipchat
|
317
|
+
[15]: https://github.com/camdez
|
318
|
+
[16]: https://github.com/tfausak
|
319
|
+
[17]: https://github.com/OrgSync
|
320
|
+
[18]: http://martinfowler.com/bliki/CircuitBreaker.html
|
321
|
+
[19]: https://github.com/alg/circuit_b
|
322
|
+
[20]: https://github.com/wsargent/circuit_breaker
|
323
|
+
[21]: https://github.com/soundcloud/simple_circuit_breaker
|
324
|
+
[22]: https://github.com/wooga/circuit_breaker
|
data/lib/stoplight.rb
CHANGED
@@ -1,29 +1,24 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
+
require 'stoplight/color'
|
4
|
+
require 'stoplight/error'
|
5
|
+
require 'stoplight/failure'
|
6
|
+
require 'stoplight/state'
|
7
|
+
|
3
8
|
require 'stoplight/data_store'
|
4
9
|
require 'stoplight/data_store/base'
|
5
10
|
require 'stoplight/data_store/memory'
|
6
11
|
require 'stoplight/data_store/redis'
|
7
|
-
|
8
|
-
require 'stoplight/failure'
|
9
|
-
require 'stoplight/light'
|
12
|
+
|
10
13
|
require 'stoplight/notifier'
|
11
14
|
require 'stoplight/notifier/base'
|
12
15
|
require 'stoplight/notifier/hip_chat'
|
13
16
|
require 'stoplight/notifier/io'
|
14
17
|
|
15
|
-
|
16
|
-
# @return [Gem::Version]
|
17
|
-
VERSION = Gem::Version.new('0.4.1')
|
18
|
-
|
19
|
-
@data_store = DataStore::Memory.new
|
20
|
-
@notifiers = [Notifier::IO.new($stderr)]
|
18
|
+
require 'stoplight/default'
|
21
19
|
|
22
|
-
|
23
|
-
|
24
|
-
attr_accessor :data_store
|
20
|
+
require 'stoplight/light/runnable'
|
21
|
+
require 'stoplight/light'
|
25
22
|
|
26
|
-
|
27
|
-
attr_accessor :notifiers
|
28
|
-
end
|
23
|
+
module Stoplight
|
29
24
|
end
|
data/lib/stoplight/data_store.rb
CHANGED
@@ -2,151 +2,5 @@
|
|
2
2
|
|
3
3
|
module Stoplight
|
4
4
|
module DataStore
|
5
|
-
KEY_PREFIX = 'stoplight'.freeze
|
6
|
-
|
7
|
-
COLOR_GREEN = 'green'.freeze
|
8
|
-
COLOR_YELLOW = 'yellow'.freeze
|
9
|
-
COLOR_RED = 'red'.freeze
|
10
|
-
COLORS = Set.new([
|
11
|
-
COLOR_GREEN,
|
12
|
-
COLOR_YELLOW,
|
13
|
-
COLOR_RED
|
14
|
-
]).freeze
|
15
|
-
|
16
|
-
STATE_UNLOCKED = 'unlocked'.freeze
|
17
|
-
STATE_LOCKED_GREEN = 'locked_green'.freeze
|
18
|
-
STATE_LOCKED_RED = 'locked_red'.freeze
|
19
|
-
STATES = Set.new([
|
20
|
-
STATE_UNLOCKED,
|
21
|
-
STATE_LOCKED_GREEN,
|
22
|
-
STATE_LOCKED_RED
|
23
|
-
]).freeze
|
24
|
-
|
25
|
-
DEFAULT_ATTEMPTS = 0
|
26
|
-
DEFAULT_FAILURES = []
|
27
|
-
DEFAULT_STATE = STATE_UNLOCKED
|
28
|
-
DEFAULT_THRESHOLD = 3
|
29
|
-
DEFAULT_TIMEOUT = 60
|
30
|
-
|
31
|
-
module_function
|
32
|
-
|
33
|
-
# @group Colors
|
34
|
-
|
35
|
-
# @param state [String]
|
36
|
-
# @param threshold [Integer]
|
37
|
-
# @param failures [Array<Failure>]
|
38
|
-
# @param timeout [Integer]
|
39
|
-
# @return [String]
|
40
|
-
def colorize(state, threshold, failures, timeout)
|
41
|
-
case
|
42
|
-
when state == STATE_LOCKED_GREEN then COLOR_GREEN
|
43
|
-
when state == STATE_LOCKED_RED then COLOR_RED
|
44
|
-
when failures.size < threshold then COLOR_GREEN
|
45
|
-
when Time.now - failures.last.time > timeout then COLOR_YELLOW
|
46
|
-
else COLOR_RED
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
# @group Validation
|
51
|
-
|
52
|
-
# @param color [String]
|
53
|
-
# @raise [ArgumentError]
|
54
|
-
def validate_color!(color)
|
55
|
-
return if valid_color?(color)
|
56
|
-
fail Error::InvalidColor, color.inspect
|
57
|
-
end
|
58
|
-
|
59
|
-
# @param color [String]
|
60
|
-
# @return [Boolean]
|
61
|
-
def valid_color?(color)
|
62
|
-
COLORS.include?(color)
|
63
|
-
end
|
64
|
-
|
65
|
-
# @param failure [Failure]
|
66
|
-
# @raise [ArgumentError]
|
67
|
-
def validate_failure!(failure)
|
68
|
-
return if valid_failure?(failure)
|
69
|
-
fail Error::InvalidFailure, failure.inspect
|
70
|
-
end
|
71
|
-
|
72
|
-
# @param failure [Failure]
|
73
|
-
# @return [Boolean]
|
74
|
-
def valid_failure?(failure)
|
75
|
-
failure.is_a?(Failure)
|
76
|
-
end
|
77
|
-
|
78
|
-
# @param state [String]
|
79
|
-
# @raise [ArgumentError]
|
80
|
-
def validate_state!(state)
|
81
|
-
return if valid_state?(state)
|
82
|
-
fail Error::InvalidState, state.inspect
|
83
|
-
end
|
84
|
-
|
85
|
-
# @param state [String]
|
86
|
-
# @return [Boolean]
|
87
|
-
def valid_state?(state)
|
88
|
-
STATES.include?(state)
|
89
|
-
end
|
90
|
-
|
91
|
-
# @param threshold [Integer]
|
92
|
-
# @raise [ArgumentError]
|
93
|
-
def validate_threshold!(threshold)
|
94
|
-
return if valid_threshold?(threshold)
|
95
|
-
fail Error::InvalidThreshold, threshold.inspect
|
96
|
-
end
|
97
|
-
|
98
|
-
# @param threshold [Integer]
|
99
|
-
# @return [Boolean]
|
100
|
-
def valid_threshold?(threshold)
|
101
|
-
threshold.is_a?(Integer) && threshold > 0
|
102
|
-
end
|
103
|
-
|
104
|
-
# @param timeout [Integer]
|
105
|
-
# @raise [ArgumentError]
|
106
|
-
def validate_timeout!(timeout)
|
107
|
-
return if valid_timeout?(timeout)
|
108
|
-
fail Error::InvalidTimeout, timeout.inspect
|
109
|
-
end
|
110
|
-
|
111
|
-
# @param timeout [Integer]
|
112
|
-
# @return [Boolean]
|
113
|
-
def valid_timeout?(timeout)
|
114
|
-
timeout.is_a?(Integer)
|
115
|
-
end
|
116
|
-
|
117
|
-
# @group Keys
|
118
|
-
|
119
|
-
# @return (see #key)
|
120
|
-
def attempts_key
|
121
|
-
key('attempts')
|
122
|
-
end
|
123
|
-
|
124
|
-
# @param name [String]
|
125
|
-
# @return (see #key)
|
126
|
-
def failures_key(name)
|
127
|
-
key('failures', name)
|
128
|
-
end
|
129
|
-
|
130
|
-
# @return (see #key)
|
131
|
-
def states_key
|
132
|
-
key('states')
|
133
|
-
end
|
134
|
-
|
135
|
-
# @return (see #key)
|
136
|
-
def thresholds_key
|
137
|
-
key('thresholds')
|
138
|
-
end
|
139
|
-
|
140
|
-
# @return (see #key)
|
141
|
-
def timeouts_key
|
142
|
-
key('timeouts')
|
143
|
-
end
|
144
|
-
|
145
|
-
# @param slug [String]
|
146
|
-
# @param suffix [String, nil]
|
147
|
-
# @return [String]
|
148
|
-
def key(slug, suffix = nil)
|
149
|
-
[KEY_PREFIX, slug, suffix].compact.join(':')
|
150
|
-
end
|
151
5
|
end
|
152
6
|
end
|