faulty 0.8.6 → 0.8.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|