Skip to content
This repository was archived by the owner on Jan 22, 2022. It is now read-only.

Commit e295949

Browse files
committed
Handle errors in methods like rails' RedisCacheStore
1 parent 4542073 commit e295949

File tree

1 file changed

+58
-35
lines changed

1 file changed

+58
-35
lines changed

lib/active_support/cache/redis_store.rb

Lines changed: 58 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ class RedisStore < Store
1313
Redis::BaseConnectionError
1414
].freeze
1515

16+
DEFAULT_ERROR_HANDLER = -> (method: nil, returning: nil, exception: nil) do
17+
if logger
18+
logger.error { "RedisStore: #{method} failed, returned #{returning.inspect}: #{exception.class}: #{exception.message}" }
19+
end
20+
end
21+
1622
attr_reader :data
1723

1824
# Instantiate the store.
@@ -65,6 +71,8 @@ def initialize(*addresses)
6571
::Redis::Store::Factory.create(*addresses, @options)
6672
end
6773

74+
@error_handler = @options[:error_handler] || DEFAULT_ERROR_HANDLER
75+
6876
super(@options)
6977
end
7078

@@ -91,14 +99,13 @@ def write(name, value, options = nil)
9199
def delete_matched(matcher, options = nil)
92100
options = merged_options(options)
93101
instrument(:delete_matched, matcher.inspect) do
94-
matcher = key_matcher(matcher, options)
95-
begin
96-
with do |store|
97-
!(keys = store.keys(matcher)).empty? && store.del(*keys)
102+
failsafe(:read_multi, returning: false) do
103+
matcher = key_matcher(matcher, options)
104+
begin
105+
with do |store|
106+
!(keys = store.keys(matcher)).empty? && store.del(*keys)
107+
end
98108
end
99-
rescue *ERRORS_TO_RESCUE
100-
raise if raise_errors?
101-
false
102109
end
103110
end
104111
end
@@ -118,16 +125,15 @@ def read_multi(*names)
118125
args.flatten!
119126

120127
instrument(:read_multi, names) do |payload|
121-
values = with { |c| c.mget(*args) }
122-
values.map! { |v| v.is_a?(ActiveSupport::Cache::Entry) ? v.value : v }
128+
failsafe(:read_multi, returning: {}) do
129+
values = with { |c| c.mget(*args) }
130+
values.map! { |v| v.is_a?(ActiveSupport::Cache::Entry) ? v.value : v }
123131

124-
Hash[names.zip(values)].reject{|k,v| v.nil?}.tap do |result|
125-
payload[:hits] = result.keys if payload
132+
Hash[names.zip(values)].reject{|k,v| v.nil?}.tap do |result|
133+
payload[:hits] = result.keys if payload
134+
end
126135
end
127136
end
128-
rescue *ERRORS_TO_RESCUE
129-
raise if raise_errors?
130-
{}
131137
end
132138

133139
def fetch_multi(*names)
@@ -147,16 +153,14 @@ def fetch_multi(*names)
147153
memo
148154
end
149155

150-
begin
156+
failsafe(:fetch_multi_write) do
151157
with do |c|
152158
c.multi do
153159
need_writes.each do |name, value|
154160
write(name, value, options)
155161
end
156162
end
157163
end
158-
rescue *ERRORS_TO_RESCUE
159-
raise if raise_errors?
160164
end
161165

162166
fetched
@@ -186,7 +190,9 @@ def fetch_multi(*names)
186190
def increment(key, amount = 1, options = {})
187191
options = merged_options(options)
188192
instrument(:increment, key, :amount => amount) do
189-
with{|c| c.incrby normalize_key(key, options), amount}
193+
failsafe(:increment) do
194+
with{|c| c.incrby normalize_key(key, options), amount}
195+
end
190196
end
191197
end
192198

@@ -214,7 +220,9 @@ def increment(key, amount = 1, options = {})
214220
def decrement(key, amount = 1, options = {})
215221
options = merged_options(options)
216222
instrument(:decrement, key, :amount => amount) do
217-
with{|c| c.decrby normalize_key(key, options), amount}
223+
failsafe(:decrement) do
224+
with{|c| c.decrby normalize_key(key, options), amount}
225+
end
218226
end
219227
end
220228

@@ -226,7 +234,9 @@ def expire(key, ttl)
226234
# Clear all the data from the store.
227235
def clear
228236
instrument(:clear, nil, nil) do
229-
with(&:flushdb)
237+
failsafe(:clear) do
238+
with(&:flushdb)
239+
end
230240
end
231241
end
232242

@@ -255,20 +265,18 @@ def reconnect
255265

256266
protected
257267
def write_entry(key, entry, options)
258-
method = options && options[:unless_exist] ? :setnx : :set
259-
with { |client| client.send method, key, entry, options }
260-
rescue *ERRORS_TO_RESCUE
261-
raise if raise_errors?
262-
false
268+
failsafe(:write_entry, returning: false) do
269+
method = options && options[:unless_exist] ? :setnx : :set
270+
with { |client| client.send method, key, entry, options }
271+
end
263272
end
264273

265274
def read_entry(key, options)
266-
entry = with { |c| c.get key, options }
267-
return unless entry
268-
entry.is_a?(Entry) ? entry : Entry.new(entry)
269-
rescue *ERRORS_TO_RESCUE
270-
raise if raise_errors?
271-
nil
275+
failsafe(:read_entry) do
276+
entry = with { |c| c.get key, options }
277+
return unless entry
278+
entry.is_a?(Entry) ? entry : Entry.new(entry)
279+
end
272280
end
273281

274282
##
@@ -277,10 +285,9 @@ def read_entry(key, options)
277285
# It's really needed and use
278286
#
279287
def delete_entry(key, options)
280-
with { |c| c.del key }
281-
rescue *ERRORS_TO_RESCUE
282-
raise if raise_errors?
283-
false
288+
failsafe(:delete_entry, returning: false) do
289+
with { |c| c.del key }
290+
end
284291
end
285292

286293
def raise_errors?
@@ -310,6 +317,22 @@ def normalize_key(*args)
310317
namespaced_key(*args)
311318
end
312319
end
320+
321+
def failsafe(method, returning: nil)
322+
yield
323+
rescue ::Redis::BaseConnectionError => e
324+
raise if raise_errors?
325+
handle_exception(exception: e, method: method, returning: returning)
326+
returning
327+
end
328+
329+
def handle_exception(exception: nil, method: nil, returning: nil)
330+
if @error_handler
331+
@error_handler.(method: method, exception: exception, returning: returning)
332+
end
333+
rescue => failsafe
334+
warn("RedisStore ignored exception in handle_exception: #{failsafe.class}: #{failsafe.message}\n #{failsafe.backtrace.join("\n ")}")
335+
end
313336
end
314337
end
315338
end

0 commit comments

Comments
 (0)