@@ -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
315338end
0 commit comments