faulty 0.8.6 → 0.8.7
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 +160 -28
- data/README.md +19 -0
- data/lib/faulty/circuit.rb +3 -5
- data/lib/faulty/deprecation.rb +1 -1
- data/lib/faulty/patch/base.rb +2 -2
- data/lib/faulty/patch/redis.rb +2 -4
- data/lib/faulty/status.rb +3 -1
- data/lib/faulty/storage/circuit_proxy.rb +1 -0
- data/lib/faulty/storage/fallback_chain.rb +8 -0
- data/lib/faulty/storage/fault_tolerant_proxy.rb +8 -1
- data/lib/faulty/storage/interface.rb +11 -0
- data/lib/faulty/storage/memory.rb +7 -0
- data/lib/faulty/storage/null.rb +5 -0
- data/lib/faulty/storage/redis.rb +56 -42
- data/lib/faulty/version.rb +1 -1
- data/lib/faulty.rb +23 -0
- metadata +6 -45
- data/.github/workflows/ci.yml +0 -66
- data/.gitignore +0 -11
- data/.rspec +0 -2
- data/.rubocop.yml +0 -97
- data/Gemfile +0 -32
- data/bin/benchmark +0 -75
- data/bin/check-version +0 -14
- data/bin/console +0 -12
- data/bin/rspec +0 -29
- data/bin/rubocop +0 -29
- data/bin/yard +0 -29
- data/bin/yardoc +0 -29
- data/bin/yri +0 -29
- data/faulty.gemspec +0 -36
data/lib/faulty/storage/redis.rb
CHANGED
@@ -9,7 +9,7 @@ class Faulty
|
|
9
9
|
# cascading failures in your application when evaluating circuits. Always
|
10
10
|
# wrap this backend with a {FaultTolerantProxy} to limit the effect of
|
11
11
|
# these types of events.
|
12
|
-
class Redis
|
12
|
+
class Redis
|
13
13
|
# Separates the time/status for history entry strings
|
14
14
|
ENTRY_SEPARATOR = ':'
|
15
15
|
|
@@ -95,7 +95,7 @@ class Faulty
|
|
95
95
|
# @param (see Interface#get_options)
|
96
96
|
# @return (see Interface#get_options)
|
97
97
|
def get_options(circuit)
|
98
|
-
json = redis { |r| r.get(options_key(circuit)) }
|
98
|
+
json = redis { |r| r.get(options_key(circuit.name)) }
|
99
99
|
return if json.nil?
|
100
100
|
|
101
101
|
JSON.parse(json, symbolize_names: true)
|
@@ -110,7 +110,7 @@ class Faulty
|
|
110
110
|
# @return (see Interface#set_options)
|
111
111
|
def set_options(circuit, stored_options)
|
112
112
|
redis do |r|
|
113
|
-
r.set(options_key(circuit), JSON.dump(stored_options), ex: options.circuit_ttl)
|
113
|
+
r.set(options_key(circuit.name), JSON.dump(stored_options), ex: options.circuit_ttl)
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
@@ -120,7 +120,7 @@ class Faulty
|
|
120
120
|
# @param (see Interface#entry)
|
121
121
|
# @return (see Interface#entry)
|
122
122
|
def entry(circuit, time, success, status)
|
123
|
-
key = entries_key(circuit)
|
123
|
+
key = entries_key(circuit.name)
|
124
124
|
result = pipe do |r|
|
125
125
|
r.sadd(list_key, circuit.name)
|
126
126
|
r.expire(list_key, options.circuit_ttl + options.list_granularity) if options.circuit_ttl
|
@@ -139,11 +139,11 @@ class Faulty
|
|
139
139
|
# @param (see Interface#open)
|
140
140
|
# @return (see Interface#open)
|
141
141
|
def open(circuit, opened_at)
|
142
|
-
key = state_key(circuit)
|
142
|
+
key = state_key(circuit.name)
|
143
143
|
ex = options.circuit_ttl
|
144
144
|
result = watch_exec(key, ['closed', nil]) do |m|
|
145
145
|
m.set(key, 'open', ex: ex)
|
146
|
-
m.set(opened_at_key(circuit), opened_at, ex: ex)
|
146
|
+
m.set(opened_at_key(circuit.name), opened_at, ex: ex)
|
147
147
|
end
|
148
148
|
|
149
149
|
result && result[0] == 'OK'
|
@@ -155,7 +155,7 @@ class Faulty
|
|
155
155
|
# @param (see Interface#reopen)
|
156
156
|
# @return (see Interface#reopen)
|
157
157
|
def reopen(circuit, opened_at, previous_opened_at)
|
158
|
-
key = opened_at_key(circuit)
|
158
|
+
key = opened_at_key(circuit.name)
|
159
159
|
result = watch_exec(key, [previous_opened_at.to_s]) do |m|
|
160
160
|
m.set(key, opened_at, ex: options.circuit_ttl)
|
161
161
|
end
|
@@ -169,11 +169,11 @@ class Faulty
|
|
169
169
|
# @param (see Interface#close)
|
170
170
|
# @return (see Interface#close)
|
171
171
|
def close(circuit)
|
172
|
-
key = state_key(circuit)
|
172
|
+
key = state_key(circuit.name)
|
173
173
|
ex = options.circuit_ttl
|
174
174
|
result = watch_exec(key, ['open']) do |m|
|
175
175
|
m.set(key, 'closed', ex: ex)
|
176
|
-
m.del(entries_key(circuit))
|
176
|
+
m.del(entries_key(circuit.name))
|
177
177
|
end
|
178
178
|
|
179
179
|
result && result[0] == 'OK'
|
@@ -187,7 +187,7 @@ class Faulty
|
|
187
187
|
# @param (see Interface#lock)
|
188
188
|
# @return (see Interface#lock)
|
189
189
|
def lock(circuit, state)
|
190
|
-
redis { |r| r.set(lock_key(circuit), state) }
|
190
|
+
redis { |r| r.set(lock_key(circuit.name), state) }
|
191
191
|
end
|
192
192
|
|
193
193
|
# Unlock a circuit
|
@@ -196,7 +196,7 @@ class Faulty
|
|
196
196
|
# @param (see Interface#unlock)
|
197
197
|
# @return (see Interface#unlock)
|
198
198
|
def unlock(circuit)
|
199
|
-
redis { |r| r.del(lock_key(circuit)) }
|
199
|
+
redis { |r| r.del(lock_key(circuit.name)) }
|
200
200
|
end
|
201
201
|
|
202
202
|
# Reset a circuit
|
@@ -205,14 +205,15 @@ class Faulty
|
|
205
205
|
# @param (see Interface#reset)
|
206
206
|
# @return (see Interface#reset)
|
207
207
|
def reset(circuit)
|
208
|
+
name = circuit.is_a?(Circuit) ? circuit.name : circuit
|
208
209
|
pipe do |r|
|
209
210
|
r.del(
|
210
|
-
entries_key(
|
211
|
-
opened_at_key(
|
212
|
-
lock_key(
|
213
|
-
options_key(
|
211
|
+
entries_key(name),
|
212
|
+
opened_at_key(name),
|
213
|
+
lock_key(name),
|
214
|
+
options_key(name)
|
214
215
|
)
|
215
|
-
r.set(state_key(
|
216
|
+
r.set(state_key(name), 'closed', ex: options.circuit_ttl)
|
216
217
|
end
|
217
218
|
end
|
218
219
|
|
@@ -224,10 +225,10 @@ class Faulty
|
|
224
225
|
def status(circuit)
|
225
226
|
futures = {}
|
226
227
|
pipe do |r|
|
227
|
-
futures[:state] = r.get(state_key(circuit))
|
228
|
-
futures[:lock] = r.get(lock_key(circuit))
|
229
|
-
futures[:opened_at] = r.get(opened_at_key(circuit))
|
230
|
-
futures[:entries] = r.lrange(entries_key(circuit), 0, -1)
|
228
|
+
futures[:state] = r.get(state_key(circuit.name))
|
229
|
+
futures[:lock] = r.get(lock_key(circuit.name))
|
230
|
+
futures[:opened_at] = r.get(opened_at_key(circuit.name))
|
231
|
+
futures[:entries] = r.lrange(entries_key(circuit.name), 0, -1)
|
231
232
|
end
|
232
233
|
|
233
234
|
state = futures[:state].value&.to_sym || :closed
|
@@ -249,7 +250,7 @@ class Faulty
|
|
249
250
|
# @param (see Interface#history)
|
250
251
|
# @return (see Interface#history)
|
251
252
|
def history(circuit)
|
252
|
-
entries = redis { |r| r.lrange(entries_key(circuit), 0, -1) }
|
253
|
+
entries = redis { |r| r.lrange(entries_key(circuit.name), 0, -1) }
|
253
254
|
map_entries(entries).reverse
|
254
255
|
end
|
255
256
|
|
@@ -260,6 +261,21 @@ class Faulty
|
|
260
261
|
redis { |r| r.sunion(*all_list_keys) }
|
261
262
|
end
|
262
263
|
|
264
|
+
# Reset all circuits
|
265
|
+
#
|
266
|
+
# This does not empty the list of circuits as returned by {#list}. This is
|
267
|
+
# because that would be a thread-usafe operation that could result in
|
268
|
+
# circuits not being in the list.
|
269
|
+
#
|
270
|
+
# This implmenentation resets circuits individually, and will be very
|
271
|
+
# slow for large numbers of circuits. It should not be used in production
|
272
|
+
# code.
|
273
|
+
#
|
274
|
+
# @return [void]
|
275
|
+
def clear
|
276
|
+
list.each { |c| reset(c) }
|
277
|
+
end
|
278
|
+
|
263
279
|
# Redis storage is not fault-tolerant
|
264
280
|
#
|
265
281
|
# @return [true]
|
@@ -276,33 +292,33 @@ class Faulty
|
|
276
292
|
[options.key_prefix, *parts].join(options.key_separator)
|
277
293
|
end
|
278
294
|
|
279
|
-
def ckey(
|
280
|
-
key('circuit',
|
295
|
+
def ckey(circuit_name, *parts)
|
296
|
+
key('circuit', circuit_name, *parts)
|
281
297
|
end
|
282
298
|
|
283
299
|
# @return [String] The key for circuit options
|
284
|
-
def options_key(
|
285
|
-
ckey(
|
300
|
+
def options_key(circuit_name)
|
301
|
+
ckey(circuit_name, 'options')
|
286
302
|
end
|
287
303
|
|
288
304
|
# @return [String] The key for circuit state
|
289
|
-
def state_key(
|
290
|
-
ckey(
|
305
|
+
def state_key(circuit_name)
|
306
|
+
ckey(circuit_name, 'state')
|
291
307
|
end
|
292
308
|
|
293
309
|
# @return [String] The key for circuit run history entries
|
294
|
-
def entries_key(
|
295
|
-
ckey(
|
310
|
+
def entries_key(circuit_name)
|
311
|
+
ckey(circuit_name, 'entries')
|
296
312
|
end
|
297
313
|
|
298
314
|
# @return [String] The key for circuit locks
|
299
|
-
def lock_key(
|
300
|
-
ckey(
|
315
|
+
def lock_key(circuit_name)
|
316
|
+
ckey(circuit_name, 'lock')
|
301
317
|
end
|
302
318
|
|
303
319
|
# @return [String] The key for circuit opened_at
|
304
|
-
def opened_at_key(
|
305
|
-
ckey(
|
320
|
+
def opened_at_key(circuit_name)
|
321
|
+
ckey(circuit_name, 'opened_at')
|
306
322
|
end
|
307
323
|
|
308
324
|
# Get the current key to add circuit names to
|
@@ -354,13 +370,11 @@ class Faulty
|
|
354
370
|
# the watch succeeds and the comparison passes
|
355
371
|
# @return [Array] An array of Redis results from the commands executed
|
356
372
|
# inside the block
|
357
|
-
def watch_exec(key, old)
|
373
|
+
def watch_exec(key, old, &block)
|
358
374
|
redis do |r|
|
359
375
|
r.watch(key) do
|
360
376
|
if old.include?(r.get(key))
|
361
|
-
r.multi
|
362
|
-
yield m
|
363
|
-
end
|
377
|
+
r.multi(&block)
|
364
378
|
else
|
365
379
|
r.unwatch
|
366
380
|
nil
|
@@ -373,9 +387,9 @@ class Faulty
|
|
373
387
|
#
|
374
388
|
# @yield [Redis] Yields the connection to the block
|
375
389
|
# @return The value returned from the block
|
376
|
-
def redis
|
390
|
+
def redis(&block)
|
377
391
|
if options.client.respond_to?(:with)
|
378
|
-
options.client.with
|
392
|
+
options.client.with(&block)
|
379
393
|
else
|
380
394
|
yield options.client
|
381
395
|
end
|
@@ -385,8 +399,8 @@ class Faulty
|
|
385
399
|
#
|
386
400
|
# @yield [Redis::Pipeline] Yields the connection to the block
|
387
401
|
# @return [void]
|
388
|
-
def pipe
|
389
|
-
redis { |r| r.pipelined
|
402
|
+
def pipe(&block)
|
403
|
+
redis { |r| r.pipelined(&block) }
|
390
404
|
end
|
391
405
|
|
392
406
|
# Map raw Redis history entries to Faulty format
|
@@ -435,7 +449,7 @@ class Faulty
|
|
435
449
|
end
|
436
450
|
|
437
451
|
def check_pool_options!
|
438
|
-
if options.client.
|
452
|
+
if options.client.instance_of?(ConnectionPool)
|
439
453
|
timeout = options.client.instance_variable_get(:@timeout)
|
440
454
|
warn(<<~MSG) if timeout > 2
|
441
455
|
Faulty recommends setting ConnectionPool timeouts <= 2 to prevent
|
data/lib/faulty/version.rb
CHANGED
data/lib/faulty.rb
CHANGED
@@ -116,6 +116,7 @@ class Faulty
|
|
116
116
|
|
117
117
|
# Get a list of all circuit names for the default instance
|
118
118
|
#
|
119
|
+
# @see #list_circuits
|
119
120
|
# @return [Array<String>] The circuit names
|
120
121
|
def list_circuits
|
121
122
|
options.storage.list
|
@@ -157,6 +158,14 @@ class Faulty
|
|
157
158
|
def disabled?
|
158
159
|
@disabled == true
|
159
160
|
end
|
161
|
+
|
162
|
+
# Reset all circuits for the default instance
|
163
|
+
#
|
164
|
+
# @see #clear
|
165
|
+
# @return [void]
|
166
|
+
def clear!
|
167
|
+
default.clear
|
168
|
+
end
|
160
169
|
end
|
161
170
|
|
162
171
|
attr_reader :options
|
@@ -255,6 +264,20 @@ class Faulty
|
|
255
264
|
options.storage.list
|
256
265
|
end
|
257
266
|
|
267
|
+
# Reset all circuits
|
268
|
+
#
|
269
|
+
# Intended for use in tests. This can be expensive and is not appropriate
|
270
|
+
# to call in production code
|
271
|
+
#
|
272
|
+
# See the documentation for your chosen backend for specific semantics and
|
273
|
+
# safety concerns. For example, the Redis backend resets all circuits, but
|
274
|
+
# it does not clear the circuit list to maintain thread-safety.
|
275
|
+
#
|
276
|
+
# @return [void]
|
277
|
+
def clear!
|
278
|
+
options.storage.clear
|
279
|
+
end
|
280
|
+
|
258
281
|
private
|
259
282
|
|
260
283
|
# Get circuit options from the {Faulty} options
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: faulty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Howard
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-08-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -80,34 +80,6 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '3.8'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: rubocop
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - '='
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: 0.81.0
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - '='
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: 0.81.0
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: rubocop-rspec
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - '='
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: 1.38.1
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - '='
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: 1.38.1
|
111
83
|
- !ruby/object:Gem::Dependency
|
112
84
|
name: timecop
|
113
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -129,24 +101,10 @@ executables: []
|
|
129
101
|
extensions: []
|
130
102
|
extra_rdoc_files: []
|
131
103
|
files:
|
132
|
-
- ".github/workflows/ci.yml"
|
133
|
-
- ".gitignore"
|
134
|
-
- ".rspec"
|
135
|
-
- ".rubocop.yml"
|
136
104
|
- ".yardopts"
|
137
105
|
- CHANGELOG.md
|
138
|
-
- Gemfile
|
139
106
|
- LICENSE.txt
|
140
107
|
- README.md
|
141
|
-
- bin/benchmark
|
142
|
-
- bin/check-version
|
143
|
-
- bin/console
|
144
|
-
- bin/rspec
|
145
|
-
- bin/rubocop
|
146
|
-
- bin/yard
|
147
|
-
- bin/yardoc
|
148
|
-
- bin/yri
|
149
|
-
- faulty.gemspec
|
150
108
|
- lib/faulty.rb
|
151
109
|
- lib/faulty/cache.rb
|
152
110
|
- lib/faulty/cache/auto_wire.rb
|
@@ -189,7 +147,10 @@ files:
|
|
189
147
|
homepage: https://github.com/ParentSquare/faulty
|
190
148
|
licenses:
|
191
149
|
- MIT
|
192
|
-
metadata:
|
150
|
+
metadata:
|
151
|
+
rubygems_mfa_required: 'true'
|
152
|
+
changelog_uri: https://github.com/ParentSquare/faulty/blob/master/CHANGELOG.md
|
153
|
+
documentation_uri: https://www.rubydoc.info/gems/faulty/0.8.7
|
193
154
|
post_install_message:
|
194
155
|
rdoc_options: []
|
195
156
|
require_paths:
|
data/.github/workflows/ci.yml
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
---
|
2
|
-
name: CI
|
3
|
-
on:
|
4
|
-
push:
|
5
|
-
tags: ['v*']
|
6
|
-
branches: [master]
|
7
|
-
pull_request:
|
8
|
-
branches: ['**']
|
9
|
-
jobs:
|
10
|
-
test:
|
11
|
-
runs-on: ubuntu-latest
|
12
|
-
strategy:
|
13
|
-
fail-fast: false
|
14
|
-
matrix:
|
15
|
-
redis: [4]
|
16
|
-
ruby: [2.3, 2.4, 2.5, 2.6, 2.7, 3.0, jruby-9.2.10, truffleruby-20.2.0]
|
17
|
-
include:
|
18
|
-
- redis: 3
|
19
|
-
ruby: 2.7
|
20
|
-
services:
|
21
|
-
redis:
|
22
|
-
image: redis
|
23
|
-
ports:
|
24
|
-
- 6379:6379
|
25
|
-
elasticsearch:
|
26
|
-
image: elasticsearch:7.13.4
|
27
|
-
ports:
|
28
|
-
- 9200:9200
|
29
|
-
options: -e="discovery.type=single-node" --health-cmd="curl http://localhost:9200/_cluster/health" --health-interval=3s --health-timeout=5s --health-retries=20
|
30
|
-
steps:
|
31
|
-
- uses: actions/checkout@v2
|
32
|
-
- uses: ruby/setup-ruby@v1
|
33
|
-
env:
|
34
|
-
REDIS_VERSION: ${{ matrix.redis }}
|
35
|
-
with:
|
36
|
-
ruby-version: ${{ matrix.ruby }}
|
37
|
-
bundler-cache: true
|
38
|
-
- run: bundle exec rubocop
|
39
|
-
if: matrix.ruby == '2.7'
|
40
|
-
- run: bin/yardoc --fail-on-warning
|
41
|
-
if: matrix.ruby == '2.7'
|
42
|
-
- run: bin/check-version
|
43
|
-
- name: start MySQL
|
44
|
-
run: sudo /etc/init.d/mysql start
|
45
|
-
- run: bundle exec rspec --format doc
|
46
|
-
env:
|
47
|
-
MYSQL_USER: root
|
48
|
-
MYSQL_PASSWORD: root
|
49
|
-
- name: Run codacy-coverage-reporter
|
50
|
-
env:
|
51
|
-
CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
|
52
|
-
if: matrix.ruby == '2.7' && env.CODACY_PROJECT_TOKEN
|
53
|
-
uses: codacy/codacy-coverage-reporter-action@master
|
54
|
-
with:
|
55
|
-
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
|
56
|
-
coverage-reports: coverage/lcov/faulty.lcov
|
57
|
-
|
58
|
-
release:
|
59
|
-
needs: test
|
60
|
-
if: startsWith(github.ref, 'refs/tags/v')
|
61
|
-
runs-on: ubuntu-latest
|
62
|
-
steps:
|
63
|
-
- uses: actions/checkout@v2
|
64
|
-
- uses: dawidd6/action-publish-gem@v1
|
65
|
-
with:
|
66
|
-
api_key: ${{secrets.RUBYGEMS_API_KEY}}
|
data/.gitignore
DELETED
data/.rspec
DELETED
data/.rubocop.yml
DELETED
@@ -1,97 +0,0 @@
|
|
1
|
-
---
|
2
|
-
require:
|
3
|
-
- rubocop-rspec
|
4
|
-
|
5
|
-
AllCops:
|
6
|
-
TargetRubyVersion: 2.3
|
7
|
-
|
8
|
-
Layout/ArgumentAlignment:
|
9
|
-
EnforcedStyle: with_fixed_indentation
|
10
|
-
|
11
|
-
Layout/CaseIndentation:
|
12
|
-
EnforcedStyle: end
|
13
|
-
|
14
|
-
Layout/ParameterAlignment:
|
15
|
-
EnforcedStyle: with_fixed_indentation
|
16
|
-
|
17
|
-
Layout/EndAlignment:
|
18
|
-
EnforcedStyleAlignWith: start_of_line
|
19
|
-
|
20
|
-
Layout/FirstArgumentIndentation:
|
21
|
-
EnforcedStyle: consistent
|
22
|
-
|
23
|
-
Layout/FirstArrayElementIndentation:
|
24
|
-
EnforcedStyle: consistent
|
25
|
-
|
26
|
-
Layout/FirstHashElementIndentation:
|
27
|
-
EnforcedStyle: consistent
|
28
|
-
|
29
|
-
Layout/LineLength:
|
30
|
-
Max: 120
|
31
|
-
|
32
|
-
Layout/MultilineMethodCallIndentation:
|
33
|
-
EnforcedStyle: indented
|
34
|
-
|
35
|
-
Layout/RescueEnsureAlignment:
|
36
|
-
Enabled: false
|
37
|
-
|
38
|
-
Lint/RaiseException:
|
39
|
-
Enabled: true
|
40
|
-
|
41
|
-
Lint/StructNewOverride:
|
42
|
-
Enabled: true
|
43
|
-
|
44
|
-
RSpec/ExampleLength:
|
45
|
-
Enabled: false
|
46
|
-
|
47
|
-
RSpec/FilePath:
|
48
|
-
Enabled: false
|
49
|
-
|
50
|
-
RSpec/NamedSubject:
|
51
|
-
Enabled: false
|
52
|
-
|
53
|
-
RSpec/MessageSpies:
|
54
|
-
Enabled: false
|
55
|
-
|
56
|
-
RSpec/MultipleExpectations:
|
57
|
-
Enabled: false
|
58
|
-
|
59
|
-
RSpec/SubjectStub:
|
60
|
-
Enabled: false
|
61
|
-
|
62
|
-
Metrics/AbcSize:
|
63
|
-
Max: 35
|
64
|
-
|
65
|
-
Metrics/BlockLength:
|
66
|
-
Enabled: false
|
67
|
-
|
68
|
-
Metrics/MethodLength:
|
69
|
-
Max: 30
|
70
|
-
|
71
|
-
Naming/MethodParameterName:
|
72
|
-
MinNameLength: 1
|
73
|
-
|
74
|
-
Style/Documentation:
|
75
|
-
Enabled: false
|
76
|
-
|
77
|
-
Style/EmptyMethod:
|
78
|
-
EnforcedStyle: expanded
|
79
|
-
|
80
|
-
Style/FrozenStringLiteralComment:
|
81
|
-
Enabled: true
|
82
|
-
EnforcedStyle: always
|
83
|
-
|
84
|
-
Style/GuardClause:
|
85
|
-
Enabled: false
|
86
|
-
|
87
|
-
Style/HashEachMethods:
|
88
|
-
Enabled: true
|
89
|
-
|
90
|
-
Style/HashTransformKeys:
|
91
|
-
Enabled: false
|
92
|
-
|
93
|
-
Style/HashTransformValues:
|
94
|
-
Enabled: false
|
95
|
-
|
96
|
-
Style/IfUnlessModifier:
|
97
|
-
Enabled: false
|
data/Gemfile
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
source 'https://rubygems.org'
|
4
|
-
|
5
|
-
gemspec
|
6
|
-
|
7
|
-
# We add non-essential gems like debugging tools and CI dependencies
|
8
|
-
# here. This also allows us to use conditional dependencies that depend on the
|
9
|
-
# platform
|
10
|
-
|
11
|
-
not_jruby = %i[ruby mingw x64_mingw].freeze
|
12
|
-
|
13
|
-
gem 'activesupport', '>= 4.2'
|
14
|
-
gem 'bundler', '>= 1.17', '< 3'
|
15
|
-
gem 'byebug', platforms: not_jruby
|
16
|
-
# Open source licensed elasticsearch
|
17
|
-
gem 'elasticsearch', '> 7', '< 7.14'
|
18
|
-
gem 'honeybadger', '>= 2.0'
|
19
|
-
gem 'irb', '~> 1.0'
|
20
|
-
# Minimum of 0.5.0 for specific error classes
|
21
|
-
gem 'mysql2', '>= 0.5.0', platforms: not_jruby
|
22
|
-
gem 'redcarpet', '~> 3.5', platforms: not_jruby
|
23
|
-
gem 'rspec_junit_formatter', '~> 0.4'
|
24
|
-
gem 'simplecov', '>= 0.17.1'
|
25
|
-
# 0.8 is incompatible with simplecov < 0.18
|
26
|
-
# https://github.com/fortissimo1997/simplecov-lcov/pull/25
|
27
|
-
gem 'simplecov-lcov', '~> 0.7', '< 0.8'
|
28
|
-
gem 'yard', '~> 0.9.25', platforms: not_jruby
|
29
|
-
|
30
|
-
if ENV['REDIS_VERSION']
|
31
|
-
gem 'redis', "~> #{ENV['REDIS_VERSION']}"
|
32
|
-
end
|
data/bin/benchmark
DELETED
@@ -1,75 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require 'bundler/setup'
|
5
|
-
require 'benchmark'
|
6
|
-
require 'faulty'
|
7
|
-
require 'redis'
|
8
|
-
require 'json'
|
9
|
-
|
10
|
-
n = 100_000
|
11
|
-
width = 25
|
12
|
-
puts "In memory circuits x#{n}"
|
13
|
-
Benchmark.bm(width) do |b|
|
14
|
-
in_memory = Faulty.new(listeners: [])
|
15
|
-
b.report('memory storage') do
|
16
|
-
n.times { in_memory.circuit(:memory).run { true } }
|
17
|
-
end
|
18
|
-
|
19
|
-
b.report('memory storage failures') do
|
20
|
-
n.times do
|
21
|
-
begin
|
22
|
-
in_memory.circuit(:memory_fail, sample_threshold: n + 1).run { raise 'fail' }
|
23
|
-
rescue StandardError
|
24
|
-
# Expected to raise here
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
in_memory_large = Faulty.new(listeners: [], storage: Faulty::Storage::Memory.new(max_sample_size: 1000))
|
30
|
-
b.report('large memory storage') do
|
31
|
-
n.times { in_memory_large.circuit(:memory_large).run { true } }
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
n = 1000
|
36
|
-
puts "\n\Redis circuits x#{n}"
|
37
|
-
Benchmark.bm(width) do |b|
|
38
|
-
redis = Faulty.new(listeners: [], storage: Faulty::Storage::Redis.new)
|
39
|
-
b.report('redis storage') do
|
40
|
-
n.times { redis.circuit(:memory).run { true } }
|
41
|
-
end
|
42
|
-
|
43
|
-
b.report('redis storage failures') do
|
44
|
-
n.times do
|
45
|
-
begin
|
46
|
-
redis.circuit(:memory_fail, sample_threshold: n + 1).run { raise 'fail' }
|
47
|
-
rescue StandardError
|
48
|
-
# Expected to raise here
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
redis_large = Faulty.new(listeners: [], storage: Faulty::Storage::Redis.new(max_sample_size: 1000))
|
54
|
-
b.report('large redis storage') do
|
55
|
-
n.times { redis_large.circuit(:memory).run { true } }
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
n = 1_000_000
|
60
|
-
puts "\n\nExtra x#{n}"
|
61
|
-
Benchmark.bm(width) do |b|
|
62
|
-
in_memory = Faulty.new(listeners: [])
|
63
|
-
|
64
|
-
log_listener = Faulty::Events::LogListener.new(Logger.new(File::NULL))
|
65
|
-
log_circuit = in_memory.circuit(:log_listener)
|
66
|
-
log_status = log_circuit.status
|
67
|
-
b.report('log listener success') do
|
68
|
-
n.times { log_listener.handle(:circuit_success, circuit: log_circuit, status: log_status) }
|
69
|
-
end
|
70
|
-
|
71
|
-
log_error = StandardError.new('test error')
|
72
|
-
b.report('log listener failure') do
|
73
|
-
n.times { log_listener.handle(:circuit_failure, error: log_error, circuit: log_circuit, status: log_status) }
|
74
|
-
end
|
75
|
-
end
|
data/bin/check-version
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
#!/usr/bin/env sh
|
2
|
-
|
3
|
-
set -e
|
4
|
-
|
5
|
-
tag="$(git describe --abbrev=0 2>/dev/null || echo)"
|
6
|
-
echo "Tag: ${tag}"
|
7
|
-
tag="${tag#v}"
|
8
|
-
echo "Git Version: ${tag}"
|
9
|
-
[ "$tag" = '' ] && exit 0
|
10
|
-
gem_version="$(ruby -r ./lib/faulty/version -e "puts Faulty.version" | tail -n1)"
|
11
|
-
echo "Gem Version: ${gem_version}"
|
12
|
-
|
13
|
-
tag_gt_version="$(ruby -r ./lib/faulty/version -e "puts Faulty.version >= Gem::Version.new('${tag}')" | tail -n1)"
|
14
|
-
test "$tag_gt_version" = true
|