breaker_machines 0.21.2 → 0.22.1
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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: deabe27c242daf0d590e59854866aa82de852bd5bf23a9dbc68ddb744c241b1d
|
|
4
|
+
data.tar.gz: 461633a405ff2e17ff26b604ea92c05a2323e777a0a439149915a3d50a7e2a5c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8ecf93848f13975efb9740e41fd2d76468ab7da07d9ba6667ae1e1e408eaa6739030c7c178631b5039f29229da4da7a37a1ae94d0f6a69172d1b199bf268c897
|
|
7
|
+
data.tar.gz: 2133bf3bf089fcbaab9974ea9cf5ea00da860c4f1a87b28df1301e022371e34143526d4c9eabafddb16fca822b53827bf154af957be0edef837b7421ce6cd0a5
|
|
@@ -221,7 +221,11 @@ module BreakerMachines
|
|
|
221
221
|
puts '-' * 80
|
|
222
222
|
|
|
223
223
|
events.each do |event|
|
|
224
|
-
timestamp =
|
|
224
|
+
timestamp = if event[:timestamp_epoch]
|
|
225
|
+
Time.at(event[:timestamp_epoch]).strftime('%Y-%m-%d %H:%M:%S')
|
|
226
|
+
else
|
|
227
|
+
format('%.3fs', event[:timestamp])
|
|
228
|
+
end
|
|
225
229
|
type = colorize_event_type(event[:type])
|
|
226
230
|
duration = event[:duration_ms] ? "#{event[:duration_ms]}ms" : '-'
|
|
227
231
|
error = event[:error_class] || '-'
|
|
@@ -15,6 +15,9 @@ module BreakerMachines
|
|
|
15
15
|
@bucket_seconds = Integer(options[:bucket_seconds] || 1)
|
|
16
16
|
raise ArgumentError, 'bucket_seconds must be positive' unless @bucket_seconds.positive?
|
|
17
17
|
|
|
18
|
+
@max_events = Integer(options[:max_events] || 100)
|
|
19
|
+
raise ArgumentError, 'max_events must be positive' unless @max_events.positive?
|
|
20
|
+
|
|
18
21
|
@warned_windows = Concurrent::Set.new
|
|
19
22
|
end
|
|
20
23
|
|
|
@@ -67,28 +70,23 @@ module BreakerMachines
|
|
|
67
70
|
keys = [success_key(circuit_name), failure_key(circuit_name)].flat_map do |key|
|
|
68
71
|
bucket_keys(key, bucket_count(@expires_in) + 1)
|
|
69
72
|
end
|
|
70
|
-
delete_counters(keys)
|
|
73
|
+
delete_counters(keys + [event_sequence_key(circuit_name)] + event_slot_keys(circuit_name))
|
|
71
74
|
end
|
|
72
75
|
|
|
73
76
|
def clear_all
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
BreakerMachines.logger&.warn(
|
|
80
|
-
"[BreakerMachines] Cache store doesn't support delete_matched. " \
|
|
81
|
-
'Individual circuit data must be cleared manually.'
|
|
82
|
-
)
|
|
83
|
-
end
|
|
77
|
+
return @cache.delete_matched(prefix_matcher) if @cache.respond_to?(:delete_matched)
|
|
78
|
+
|
|
79
|
+
warn_clear_all_unsupported
|
|
80
|
+
rescue NotImplementedError
|
|
81
|
+
warn_clear_all_unsupported
|
|
84
82
|
end
|
|
85
83
|
|
|
86
84
|
def record_event_with_details(circuit_name, type, duration, error: nil, new_state: nil)
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
now = monotonic_time
|
|
89
86
|
event = {
|
|
90
87
|
type: type,
|
|
91
|
-
timestamp:
|
|
88
|
+
timestamp: now,
|
|
89
|
+
timestamp_epoch: BreakerMachines.monotonic_to_epoch(now),
|
|
92
90
|
duration_ms: (duration * 1000).round(2)
|
|
93
91
|
}
|
|
94
92
|
|
|
@@ -96,15 +94,24 @@ module BreakerMachines
|
|
|
96
94
|
event[:error_message] = error.message if error
|
|
97
95
|
event[:new_state] = new_state if new_state
|
|
98
96
|
|
|
99
|
-
|
|
100
|
-
events.shift while events.size > (@max_events || 100)
|
|
97
|
+
return append_event(circuit_name, event) unless @cache.respond_to?(:increment)
|
|
101
98
|
|
|
102
|
-
@cache.
|
|
99
|
+
sequence = @cache.increment(event_sequence_key(circuit_name), 1, expires_in: @expires_in)
|
|
100
|
+
return false unless sequence
|
|
101
|
+
|
|
102
|
+
@cache.write(event_slot_key(circuit_name, sequence % @max_events),
|
|
103
|
+
event.merge(sequence: sequence), expires_in: @expires_in)
|
|
103
104
|
end
|
|
104
105
|
|
|
105
106
|
def event_log(circuit_name, limit)
|
|
106
|
-
events = @cache.
|
|
107
|
-
|
|
107
|
+
events = if @cache.respond_to?(:increment)
|
|
108
|
+
read_values(event_slot_keys(circuit_name)).sort_by do |event|
|
|
109
|
+
[event[:timestamp_epoch], event[:sequence]]
|
|
110
|
+
end
|
|
111
|
+
else
|
|
112
|
+
@cache.read(events_key(circuit_name)) || []
|
|
113
|
+
end
|
|
114
|
+
events.last(limit).map { |event| local_event(event) }
|
|
108
115
|
end
|
|
109
116
|
|
|
110
117
|
def with_timeout(_timeout_ms)
|
|
@@ -165,9 +172,39 @@ module BreakerMachines
|
|
|
165
172
|
|
|
166
173
|
# read_multi is a single round trip; stores without it read each bucket.
|
|
167
174
|
def read_counters(keys)
|
|
168
|
-
|
|
175
|
+
read_values(keys, raw: true)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def read_values(keys, **options)
|
|
179
|
+
return @cache.read_multi(*keys, **options).values if @cache.respond_to?(:read_multi)
|
|
180
|
+
|
|
181
|
+
keys.filter_map { |key| @cache.read(key, options) }
|
|
182
|
+
end
|
|
169
183
|
|
|
170
|
-
|
|
184
|
+
def append_event(circuit_name, event)
|
|
185
|
+
events = @cache.fetch(events_key(circuit_name)) { [] }
|
|
186
|
+
events << event
|
|
187
|
+
events.shift while events.size > @max_events
|
|
188
|
+
@cache.write(events_key(circuit_name), events, expires_in: @expires_in)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def local_event(event)
|
|
192
|
+
epoch = event[:timestamp_epoch]
|
|
193
|
+
local = event.except(:sequence)
|
|
194
|
+
epoch ? local.merge(timestamp: BreakerMachines.epoch_to_monotonic(epoch)) : local
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def prefix_matcher
|
|
198
|
+
return "#{@prefix.gsub(/[?*\[\]\\]/) { |char| "\\#{char}" }}:*" if @cache.respond_to?(:redis)
|
|
199
|
+
|
|
200
|
+
/^#{Regexp.escape(@prefix)}:/
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def warn_clear_all_unsupported
|
|
204
|
+
BreakerMachines.logger&.warn(
|
|
205
|
+
"[BreakerMachines] #{@cache.class} doesn't support delete_matched. " \
|
|
206
|
+
'Individual circuit data must be cleared manually.'
|
|
207
|
+
)
|
|
171
208
|
end
|
|
172
209
|
|
|
173
210
|
def delete_counters(keys)
|
|
@@ -210,6 +247,18 @@ module BreakerMachines
|
|
|
210
247
|
"#{@prefix}:#{circuit_name}:events"
|
|
211
248
|
end
|
|
212
249
|
|
|
250
|
+
def event_sequence_key(circuit_name)
|
|
251
|
+
"#{@prefix}:#{circuit_name}:event_sequence"
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def event_slot_key(circuit_name, slot)
|
|
255
|
+
"#{@prefix}:#{circuit_name}:event:#{slot}"
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def event_slot_keys(circuit_name)
|
|
259
|
+
Array.new(@max_events) { |slot| event_slot_key(circuit_name, slot) }
|
|
260
|
+
end
|
|
261
|
+
|
|
213
262
|
def monotonic_time
|
|
214
263
|
BreakerMachines.monotonic_time
|
|
215
264
|
end
|
|
@@ -46,9 +46,11 @@ module BreakerMachines
|
|
|
46
46
|
def record_event_with_details(circuit_name, type, duration, error: nil, new_state: nil)
|
|
47
47
|
events = @event_logs.compute_if_absent(circuit_name) { Concurrent::Array.new }
|
|
48
48
|
|
|
49
|
+
now = monotonic_time
|
|
49
50
|
event = {
|
|
50
51
|
type: type,
|
|
51
|
-
timestamp:
|
|
52
|
+
timestamp: now,
|
|
53
|
+
timestamp_epoch: BreakerMachines.monotonic_to_epoch(@start_time + now),
|
|
52
54
|
duration_ms: (duration * 1000).round(2)
|
|
53
55
|
}
|
|
54
56
|
|
|
@@ -24,6 +24,7 @@ module BreakerMachines
|
|
|
24
24
|
super
|
|
25
25
|
# Native extension is guaranteed to be available when this class is loaded
|
|
26
26
|
@backend = BreakerMachinesNative::Storage.new
|
|
27
|
+
@epoch_origin = BreakerMachines.monotonic_to_epoch(BreakerMachines.monotonic_time)
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
# Check if using native backend
|
|
@@ -81,7 +82,9 @@ module BreakerMachines
|
|
|
81
82
|
end
|
|
82
83
|
|
|
83
84
|
def event_log(circuit_name, limit)
|
|
84
|
-
@backend.event_log(circuit_name.to_s, limit)
|
|
85
|
+
@backend.event_log(circuit_name.to_s, limit).map do |event|
|
|
86
|
+
event.merge(timestamp_epoch: @epoch_origin + event[:timestamp])
|
|
87
|
+
end
|
|
85
88
|
end
|
|
86
89
|
|
|
87
90
|
def with_timeout(_timeout_ms)
|