faulty 0.1.0 → 0.2.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.
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Faulty
3
+ class Faulty
4
4
  module Events
5
5
  # The interface required to implement a event listener
6
6
  #
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Faulty
3
+ class Faulty
4
4
  module Events
5
5
  # A default listener that logs Faulty events
6
6
  class LogListener
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Faulty
3
+ class Faulty
4
4
  module Events
5
5
  # The default event dispatcher for Faulty
6
6
  class Notifier
@@ -11,6 +11,9 @@ module Faulty
11
11
 
12
12
  # Notify all listeners of an event
13
13
  #
14
+ # If a listener raises an error while handling an event, that error will
15
+ # be captured and written to STDERR.
16
+ #
14
17
  # @param event [Symbol] The event name
15
18
  # @param payload [Hash] A hash of event payload data. The payload keys
16
19
  # differ between events, but should be consistent across calls for a
@@ -18,7 +21,13 @@ module Faulty
18
21
  def notify(event, payload)
19
22
  raise ArgumentError, "Unknown event #{event}" unless EVENTS.include?(event)
20
23
 
21
- @listeners.each { |l| l.handle(event, payload) }
24
+ @listeners.each do |listener|
25
+ begin
26
+ listener.handle(event, payload)
27
+ rescue StandardError => e
28
+ warn "Faulty listener #{listener.class.name} crashed: #{e.message}"
29
+ end
30
+ end
22
31
  end
23
32
  end
24
33
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Faulty
3
+ class Faulty
4
4
  # A struct that cannot be modified after initialization
5
5
  module ImmutableOptions
6
6
  # @param hash [Hash] A hash of attributes to initialize with
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Faulty
3
+ class Faulty
4
4
  # An approximation of the `Result` type from some strongly-typed languages.
5
5
  #
6
6
  # F#: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/results
@@ -53,7 +53,7 @@ module Faulty
53
53
  #
54
54
  # @param ok An ok value
55
55
  # @param error [Error] An error instance
56
- def initialize(ok: NOTHING, error: NOTHING) # rubocop:disable Naming/MethodParameterName
56
+ def initialize(ok: NOTHING, error: NOTHING)
57
57
  if ok.equal?(NOTHING) && error.equal?(NOTHING)
58
58
  raise ArgumentError, 'Result must have an ok or error value'
59
59
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Faulty
3
+ class Faulty
4
4
  # The status of a circuit
5
5
  #
6
6
  # Includes information like the state and locks. Also calculates
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Faulty
3
+ class Faulty
4
4
  # The namespace for Faulty storage
5
5
  module Storage
6
6
  end
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Faulty
3
+ class Faulty
4
4
  module Storage
5
5
  # A wrapper for storage backends that may raise errors
6
6
  #
7
- # {Scope} automatically wraps all non-fault-tolerant storage backends with
7
+ # {Faulty#initialize} automatically wraps all non-fault-tolerant storage backends with
8
8
  # this class.
9
9
  #
10
10
  # If the storage backend raises a `StandardError`, it will be captured and
@@ -53,8 +53,8 @@ module Faulty
53
53
  # @see Interface#open
54
54
  # @param (see Interface#open)
55
55
  # @return (see Interface#open)
56
- def open(circuit)
57
- @storage.open(circuit)
56
+ def open(circuit, opened_at)
57
+ @storage.open(circuit, opened_at)
58
58
  rescue StandardError => e
59
59
  options.notifier.notify(:storage_failure, circuit: circuit, action: :open, error: e)
60
60
  false
@@ -65,8 +65,8 @@ module Faulty
65
65
  # @see Interface#reopen
66
66
  # @param (see Interface#reopen)
67
67
  # @return (see Interface#reopen)
68
- def reopen(circuit)
69
- @storage.reopen(circuit)
68
+ def reopen(circuit, opened_at, previous_opened_at)
69
+ @storage.reopen(circuit, opened_at, previous_opened_at)
70
70
  rescue StandardError => e
71
71
  options.notifier.notify(:storage_failure, circuit: circuit, action: :reopen, error: e)
72
72
  false
@@ -167,10 +167,8 @@ module Faulty
167
167
  # @return [Status] The stub status
168
168
  def stub_status(circuit)
169
169
  Faulty::Status.new(
170
- cool_down: circuit.options.cool_down,
171
- stub: true,
172
- sample_threshold: circuit.options.sample_threshold,
173
- rate_threshold: circuit.options.rate_threshold
170
+ options: circuit.options,
171
+ stub: true
174
172
  )
175
173
  end
176
174
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Faulty
3
+ class Faulty
4
4
  module Storage
5
5
  # The interface required for a storage backend implementation
6
6
  #
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Faulty
3
+ class Faulty
4
4
  module Storage
5
5
  # The default in-memory storage for circuits
6
6
  #
@@ -83,7 +83,7 @@ module Faulty
83
83
  memory = fetch(circuit)
84
84
  memory.runs.borrow do |runs|
85
85
  runs.push([time, success])
86
- runs.pop if runs.size > options.max_sample_size
86
+ runs.shift if runs.size > options.max_sample_size
87
87
  end
88
88
  memory.status(circuit.options)
89
89
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Faulty
3
+ class Faulty
4
4
  module Storage
5
5
  class Redis # rubocop:disable Metrics/ClassLength
6
6
  # Separates the time/status for history entry strings
@@ -97,7 +97,7 @@ module Faulty
97
97
  # @return (see Interface#open)
98
98
  def open(circuit, opened_at)
99
99
  redis do |r|
100
- opened = compare_and_set(r, state_key(circuit), ['closed', nil], 'open')
100
+ opened = compare_and_set(r, state_key(circuit), ['closed', nil], 'open', ex: options.circuit_ttl)
101
101
  r.set(opened_at_key(circuit), opened_at, ex: options.circuit_ttl) if opened
102
102
  opened
103
103
  end
@@ -110,7 +110,7 @@ module Faulty
110
110
  # @return (see Interface#reopen)
111
111
  def reopen(circuit, opened_at, previous_opened_at)
112
112
  redis do |r|
113
- compare_and_set(r, opened_at_key(circuit), [previous_opened_at.to_s], opened_at)
113
+ compare_and_set(r, opened_at_key(circuit), [previous_opened_at.to_s], opened_at, ex: options.circuit_ttl)
114
114
  end
115
115
  end
116
116
 
@@ -121,7 +121,7 @@ module Faulty
121
121
  # @return (see Interface#close)
122
122
  def close(circuit)
123
123
  redis do |r|
124
- closed = compare_and_set(r, state_key(circuit), ['open'], 'closed')
124
+ closed = compare_and_set(r, state_key(circuit), ['open'], 'closed', ex: options.circuit_ttl)
125
125
  r.del(entries_key(circuit)) if closed
126
126
  closed
127
127
  end
@@ -287,16 +287,16 @@ module Faulty
287
287
  # @param new [String] The new value to set if the compare passes
288
288
  # @return [Boolean] True if the value was set to `new`, false if the CAS
289
289
  # failed
290
- def compare_and_set(redis, key, old, new)
291
- result = redis.watch(key) do
290
+ def compare_and_set(redis, key, old, new, ex:)
291
+ redis.watch(key) do
292
292
  if old.include?(redis.get(key))
293
- redis.multi { |m| m.set(key, new) }
293
+ result = redis.multi { |m| m.set(key, new, ex: ex) }
294
+ result && result[0] == 'OK'
294
295
  else
295
296
  redis.unwatch
297
+ false
296
298
  end
297
299
  end
298
-
299
- result[0] == 'OK'
300
300
  end
301
301
 
302
302
  # Yield a Redis connection
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Faulty
3
+ class Faulty
4
4
  # The current Faulty version
5
5
  def self.version
6
- Gem::Version.new('0.1.0')
6
+ Gem::Version.new('0.2.0')
7
7
  end
8
8
  end
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.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Howard
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-27 00:00:00.000000000 Z
11
+ date: 2020-10-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -24,54 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.0'
27
- - !ruby/object:Gem::Dependency
28
- name: activesupport
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '4.2'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '4.2'
41
- - !ruby/object:Gem::Dependency
42
- name: bundler
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '1.17'
48
- - - "<"
49
- - !ruby/object:Gem::Version
50
- version: '3'
51
- type: :development
52
- prerelease: false
53
- version_requirements: !ruby/object:Gem::Requirement
54
- requirements:
55
- - - ">="
56
- - !ruby/object:Gem::Version
57
- version: '1.17'
58
- - - "<"
59
- - !ruby/object:Gem::Version
60
- version: '3'
61
- - !ruby/object:Gem::Dependency
62
- name: byebug
63
- requirement: !ruby/object:Gem::Requirement
64
- requirements:
65
- - - "~>"
66
- - !ruby/object:Gem::Version
67
- version: '11.0'
68
- type: :development
69
- prerelease: false
70
- version_requirements: !ruby/object:Gem::Requirement
71
- requirements:
72
- - - "~>"
73
- - !ruby/object:Gem::Version
74
- version: '11.0'
75
27
  - !ruby/object:Gem::Dependency
76
28
  name: connection_pool
77
29
  requirement: !ruby/object:Gem::Requirement
@@ -87,33 +39,19 @@ dependencies:
87
39
  - !ruby/object:Gem::Version
88
40
  version: '2.0'
89
41
  - !ruby/object:Gem::Dependency
90
- name: irb
42
+ name: honeybadger
91
43
  requirement: !ruby/object:Gem::Requirement
92
44
  requirements:
93
- - - "~>"
94
- - !ruby/object:Gem::Version
95
- version: '1.0'
96
- type: :development
97
- prerelease: false
98
- version_requirements: !ruby/object:Gem::Requirement
99
- requirements:
100
- - - "~>"
101
- - !ruby/object:Gem::Version
102
- version: '1.0'
103
- - !ruby/object:Gem::Dependency
104
- name: redcarpet
105
- requirement: !ruby/object:Gem::Requirement
106
- requirements:
107
- - - "~>"
45
+ - - ">="
108
46
  - !ruby/object:Gem::Version
109
- version: '3.5'
47
+ version: '2.0'
110
48
  type: :development
111
49
  prerelease: false
112
50
  version_requirements: !ruby/object:Gem::Requirement
113
51
  requirements:
114
- - - "~>"
52
+ - - ">="
115
53
  - !ruby/object:Gem::Version
116
- version: '3.5'
54
+ version: '2.0'
117
55
  - !ruby/object:Gem::Dependency
118
56
  name: redis
119
57
  requirement: !ruby/object:Gem::Requirement
@@ -142,20 +80,6 @@ dependencies:
142
80
  - - "~>"
143
81
  - !ruby/object:Gem::Version
144
82
  version: '3.8'
145
- - !ruby/object:Gem::Dependency
146
- name: rspec_junit_formatter
147
- requirement: !ruby/object:Gem::Requirement
148
- requirements:
149
- - - "~>"
150
- - !ruby/object:Gem::Version
151
- version: '0.4'
152
- type: :development
153
- prerelease: false
154
- version_requirements: !ruby/object:Gem::Requirement
155
- requirements:
156
- - - "~>"
157
- - !ruby/object:Gem::Version
158
- version: '0.4'
159
83
  - !ruby/object:Gem::Dependency
160
84
  name: rubocop
161
85
  requirement: !ruby/object:Gem::Requirement
@@ -184,26 +108,6 @@ dependencies:
184
108
  - - '='
185
109
  - !ruby/object:Gem::Version
186
110
  version: 1.38.1
187
- - !ruby/object:Gem::Dependency
188
- name: simplecov
189
- requirement: !ruby/object:Gem::Requirement
190
- requirements:
191
- - - ">="
192
- - !ruby/object:Gem::Version
193
- version: 0.17.1
194
- - - "<"
195
- - !ruby/object:Gem::Version
196
- version: '0.18'
197
- type: :development
198
- prerelease: false
199
- version_requirements: !ruby/object:Gem::Requirement
200
- requirements:
201
- - - ">="
202
- - !ruby/object:Gem::Version
203
- version: 0.17.1
204
- - - "<"
205
- - !ruby/object:Gem::Version
206
- version: '0.18'
207
111
  - !ruby/object:Gem::Dependency
208
112
  name: timecop
209
113
  requirement: !ruby/object:Gem::Requirement
@@ -218,21 +122,7 @@ dependencies:
218
122
  - - ">="
219
123
  - !ruby/object:Gem::Version
220
124
  version: '0.9'
221
- - !ruby/object:Gem::Dependency
222
- name: yard
223
- requirement: !ruby/object:Gem::Requirement
224
- requirements:
225
- - - "~>"
226
- - !ruby/object:Gem::Version
227
- version: 0.9.25
228
- type: :development
229
- prerelease: false
230
- version_requirements: !ruby/object:Gem::Requirement
231
- requirements:
232
- - - "~>"
233
- - !ruby/object:Gem::Version
234
- version: 0.9.25
235
- description:
125
+ description:
236
126
  email:
237
127
  - jmhoward0@gmail.com
238
128
  executables: []
@@ -244,6 +134,7 @@ files:
244
134
  - ".rubocop.yml"
245
135
  - ".travis.yml"
246
136
  - ".yardopts"
137
+ - CHANGELOG.md
247
138
  - Gemfile
248
139
  - LICENSE.txt
249
140
  - README.md
@@ -267,12 +158,12 @@ files:
267
158
  - lib/faulty/error.rb
268
159
  - lib/faulty/events.rb
269
160
  - lib/faulty/events/callback_listener.rb
161
+ - lib/faulty/events/honeybadger_listener.rb
270
162
  - lib/faulty/events/listener_interface.rb
271
163
  - lib/faulty/events/log_listener.rb
272
164
  - lib/faulty/events/notifier.rb
273
165
  - lib/faulty/immutable_options.rb
274
166
  - lib/faulty/result.rb
275
- - lib/faulty/scope.rb
276
167
  - lib/faulty/status.rb
277
168
  - lib/faulty/storage.rb
278
169
  - lib/faulty/storage/fault_tolerant_proxy.rb
@@ -284,7 +175,7 @@ homepage: https://github.com/ParentSquare/faulty
284
175
  licenses:
285
176
  - MIT
286
177
  metadata: {}
287
- post_install_message:
178
+ post_install_message:
288
179
  rdoc_options: []
289
180
  require_paths:
290
181
  - lib
@@ -299,8 +190,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
299
190
  - !ruby/object:Gem::Version
300
191
  version: '0'
301
192
  requirements: []
302
- rubygems_version: 3.1.4
303
- signing_key:
193
+ rubygems_version: 3.0.8
194
+ signing_key:
304
195
  specification_version: 4
305
196
  summary: Fault-tolerance tools for ruby based on circuit-breakers
306
197
  test_files: []