Skip to content

Commit f33f858

Browse files
author
Shaun Carlson
committed
handle cache errors in cache class, rewrite fetch method
1 parent 7b72849 commit f33f858

9 files changed

Lines changed: 248 additions & 68 deletions

File tree

README.md

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ end
3030

3131
_*This is already done for you in Rails_
3232

33-
Then declare some cache finder methods. Cached finders can be defined for individual fields or defined as composites for mulitple fields
33+
Then declare some cache finder methods. Cached finders can be defined for individual fields or defined as composites for
34+
multiple fields
3435

3536
```ruby
3637
class Customer < ::ActiveRemote::Base
@@ -42,7 +43,8 @@ class Customer < ::ActiveRemote::Base
4243
end
4344
```
4445

45-
Now that you have a model that has cached finders on it you can use the `cached_search`, `cached_find`, or dynamic cached finder methods on the model to use the cache before you issue the AR search/find method.
46+
Now that you have a model that has cached finders on it you can use the `cached_search`, `cached_find`, or dynamic
47+
cached finder methods on the model to use the cache before you issue the AR search/find method.
4648

4749
```ruby
4850
customer = ::Customer.cached_find_by_id(1) # => <Customer id=1>
@@ -62,13 +64,14 @@ customer = ::Customer.cached_find_by_name("name") # => NoMethodError
6264

6365
### Configuring the cache provider
6466

65-
ActiveRemote::Cached relies on an ActiveSupport::Cache-compatible cache provider. The cache is initialized with a simple memory store (defaults to 32MB), but can be overridden via `ActiveRemote::Cached.cache`:
67+
ActiveRemote::Cached relies on an ActiveSupport::Cache-compatible cache provider. The cache is initialized with a simple
68+
memory store (defaults to 32MB), but can be overridden via `ActiveRemote::Cached.cache`:
6669

6770
```ruby
6871
ActiveRemote::Cached.cache(Your::ActiveSupport::Cache::Compatible::Provider.new)
6972
```
7073

71-
In Rails apps, the memory store is replaced the whatever Rails is using as it's cache store.
74+
In Rails apps, the memory store is replaced with whatever Rails is using as it's cache store.
7275

7376
#### Default options
7477

@@ -78,11 +81,19 @@ The default cache options used when interacting with the cache can be specified
7881
ActiveRemote::Cached.default_options(:expires_in => 1.hour)
7982
```
8083

81-
In Rails apps, the :race_condition_ttl option defaults to 5 seconds.
84+
In Rails apps, the options are:
85+
86+
| Configuration Option | Default | Description |
87+
|-----------------------|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
88+
| `:race_condition_ttl` | `5.seconds` | See [ActiveSupport::Cache::Store documentation](https://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html) |
89+
| `:expires_in` | `5.minutes` | See [ActiveSupport::Cache::Store documentation](https://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html) |
90+
| `:handle_cache_error` | `false` | When true, cache errors will be handled and optionally sent to handler and return value will be as if cache missed, when cache errors will raise to application |
91+
| `:cache_error_proc` | `nil` | Can be a proc that accepts a single value, the cache error raised, to be used in any kind of error handling you might want |
8292

8393
#### Local overrides
8494

85-
Each finder as takes an optional options hash that will override the options passed to the caching provider (override from the global defaults setup for ActiveRemote::Cached)
95+
Each finder takes an optional options hash that will override the options passed to the caching provider (override from
96+
the global defaults setup for ActiveRemote::Cached)
8697

8798
```ruby
8899
customer = ::Customer.cached_find_by_id(1, :expires_in => 15.minutes)

lib/active_remote/cached.rb

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ def self.cache(cache_provider = nil)
2424
@cache_provider
2525
end
2626

27+
def self.cache_options
28+
::ActiveRemote::Cached.default_options.except(:cache_error_proc, :handle_cache_error)
29+
end
30+
2731
def self.default_options(options = nil)
2832
if options
2933
@default_options = options
@@ -145,7 +149,7 @@ def _define_cached_delete_method(method_name, *method_arguments, cached_finder_o
145149
# ::ActiveRemote::Cached.cache.delete([name, user_guid])
146150
# end
147151
def self.#{method_name}(#{expanded_method_args}, __active_remote_cached_options = {})
148-
__active_remote_cached_options = ::ActiveRemote::Cached.default_options.merge(#{cached_finder_options}).merge(__active_remote_cached_options)
152+
__active_remote_cached_options = ::ActiveRemote::Cached.cache_options.merge(#{cached_finder_options}).merge(__active_remote_cached_options)
149153
namespace = __active_remote_cached_options.delete(:namespace)
150154
find_cache_key = [
151155
RUBY_AND_ACTIVE_SUPPORT_VERSION,
@@ -179,7 +183,7 @@ def _define_cached_exist_find_method(method_name, *method_arguments, cached_find
179183
# ::ActiveRemote::Cached.cache.exist?([name, user_guid])
180184
# end
181185
def self.#{method_name}(#{expanded_method_args}, __active_remote_cached_options = {})
182-
__active_remote_cached_options = ::ActiveRemote::Cached.default_options.merge(#{cached_finder_options}).merge(__active_remote_cached_options)
186+
__active_remote_cached_options = ::ActiveRemote::Cached.cache_options.merge(#{cached_finder_options}).merge(__active_remote_cached_options)
183187
namespace = __active_remote_cached_options.delete(:namespace)
184188
cache_key = [
185189
RUBY_AND_ACTIVE_SUPPORT_VERSION,
@@ -190,9 +194,6 @@ def self.#{method_name}(#{expanded_method_args}, __active_remote_cached_options
190194
].compact
191195
192196
::ActiveRemote::Cached.cache.exist?(cache_key)
193-
rescue => e
194-
return false if e.message.include?("upstream failure")
195-
raise
196197
end
197198
RUBY
198199

@@ -209,7 +210,7 @@ def _define_cached_exist_search_method(method_name, *method_arguments, cached_fi
209210
# ::ActiveRemote::Cached.cache.exist?([namespace, name, "#search", user_guid])
210211
# end
211212
def self.#{method_name}(#{expanded_method_args}, __active_remote_cached_options = {})
212-
__active_remote_cached_options = ::ActiveRemote::Cached.default_options.merge(#{cached_finder_options}).merge(__active_remote_cached_options)
213+
__active_remote_cached_options = ::ActiveRemote::Cached.cache_options.merge(#{cached_finder_options}).merge(__active_remote_cached_options)
213214
namespace = __active_remote_cached_options.delete(:namespace)
214215
cache_key = [
215216
RUBY_AND_ACTIVE_SUPPORT_VERSION,
@@ -220,9 +221,6 @@ def self.#{method_name}(#{expanded_method_args}, __active_remote_cached_options
220221
].compact
221222
222223
::ActiveRemote::Cached.cache.exist?(cache_key)
223-
rescue => e
224-
return false if e.message.include?("upstream failure")
225-
raise
226224
end
227225
RUBY
228226

@@ -241,7 +239,7 @@ def _define_cached_find_method(method_name, *method_arguments, cached_finder_opt
241239

242240
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
243241
# def self.cached_find_by_user_guid(user_guid, options = {})
244-
# options = ::ActiveRemote::Cached.default_options.merge({}).merge(options)
242+
# options = ::ActiveRemote::Cached.cache_options.merge({}).merge(options)
245243
#
246244
# ::ActiveRemote::Cached.cache.fetch([namespace, name, "#find", user_guid], options) do
247245
# self.find(:user_guid => user_guid)
@@ -252,7 +250,7 @@ def _define_cached_find_method(method_name, *method_arguments, cached_finder_opt
252250
# of the result object is maintained for requests/responses
253251
#
254252
def self.#{method_name}(#{expanded_method_args}, __active_remote_cached_options = {})
255-
__active_remote_cached_options = ::ActiveRemote::Cached.default_options.merge(#{cached_finder_options}).merge(__active_remote_cached_options)
253+
__active_remote_cached_options = ::ActiveRemote::Cached.cache_options.merge(#{cached_finder_options}).merge(__active_remote_cached_options)
256254
namespace = __active_remote_cached_options.delete(:namespace)
257255
cache_key = [
258256
RUBY_AND_ACTIVE_SUPPORT_VERSION,
@@ -269,9 +267,6 @@ def self.#{method_name}(#{expanded_method_args}, __active_remote_cached_options
269267
self.find(#{expanded_search_args})
270268
end
271269
end
272-
rescue => e
273-
return self.find(#{expanded_search_args}) if e.message.include?("upstream failure")
274-
raise
275270
end
276271
RUBY
277272
end
@@ -288,7 +283,7 @@ def _define_cached_search_method(method_name, *method_arguments, cached_finder_o
288283

289284
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
290285
# def self.cached_search_by_user_guid(user_guid, options = {})
291-
# options = ::ActiveRemote::Cached.default_options.merge({}).merge(options)
286+
# options = ::ActiveRemote::Cached.cache_options.merge({}).merge(options)
292287
#
293288
# ::ActiveRemote::Cached.cache.fetch([namespace, name, "#search", user_guid], options) do
294289
# if block_given?
@@ -303,7 +298,7 @@ def _define_cached_search_method(method_name, *method_arguments, cached_finder_o
303298
# of the result object is maintained for requests/responses
304299
#
305300
def self.#{method_name}(#{expanded_method_args}, __active_remote_cached_options = {})
306-
__active_remote_cached_options = ::ActiveRemote::Cached.default_options.merge(#{cached_finder_options}).merge(__active_remote_cached_options)
301+
__active_remote_cached_options = ::ActiveRemote::Cached.cache_options.merge(#{cached_finder_options}).merge(__active_remote_cached_options)
307302
namespace = __active_remote_cached_options.delete(:namespace)
308303
cache_key = [
309304
RUBY_AND_ACTIVE_SUPPORT_VERSION,
@@ -320,9 +315,6 @@ def self.#{method_name}(#{expanded_method_args}, __active_remote_cached_options
320315
self.search(#{expanded_search_args})
321316
end
322317
end
323-
rescue => e
324-
return self.search(#{expanded_search_args}) if e.message.include?("upstream failure")
325-
raise
326318
end
327319
RUBY
328320
end
@@ -339,7 +331,7 @@ def _define_cached_search_bang_method(method_name, *method_arguments, cached_fin
339331

340332
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
341333
# def self.cached_search_by_user_guid!(user_guid, options = {})
342-
# options = ::ActiveRemote::Cached.default_options.merge({}).merge(options)
334+
# options = ::ActiveRemote::Cached.cache_options.merge({}).merge(options)
343335
#
344336
# ::ActiveRemote::Cached.cache.fetch([namespace, name, "#search", user_guid], options) do
345337
# results = []
@@ -359,7 +351,7 @@ def _define_cached_search_bang_method(method_name, *method_arguments, cached_fin
359351
# of the result object is maintained for requests/responses
360352
#
361353
def self.#{method_name}(#{expanded_method_args}, __active_remote_cached_options = {})
362-
__active_remote_cached_options = ::ActiveRemote::Cached.default_options.merge(#{cached_finder_options}).merge(__active_remote_cached_options)
354+
__active_remote_cached_options = ::ActiveRemote::Cached.cache_options.merge(#{cached_finder_options}).merge(__active_remote_cached_options)
363355
namespace = __active_remote_cached_options.delete(:namespace)
364356
cache_key = [
365357
RUBY_AND_ACTIVE_SUPPORT_VERSION,
@@ -381,13 +373,6 @@ def self.#{method_name}(#{expanded_method_args}, __active_remote_cached_options
381373
raise ::ActiveRemote::RemoteRecordNotFound.new(self.class) if results.first.nil?
382374
results
383375
end
384-
rescue => e
385-
if e.message.include?("upstream failure")
386-
results = self.search(#{expanded_search_args})
387-
raise ::ActiveRemote::RemoteRecordNotFound.new(self.class) if results.first.nil?
388-
return results
389-
end
390-
raise
391376
end
392377
RUBY
393378
end

lib/active_remote/cached/cache.rb

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ def initialize(new_cache_provider)
2020
def delete(*args)
2121
nested_cache_provider.delete(*args)
2222
super
23+
rescue => e
24+
raise e unless ::ActiveRemote::Cached.default_options[:handle_cache_error]
25+
error_proc = ::ActiveRemote::Cached.default_options[:cache_error_proc]
26+
error_proc.call(e) if error_proc.respond_to?(:call)
27+
28+
nil
2329
end
2430

2531
def enable_nested_caching!
@@ -28,10 +34,20 @@ def enable_nested_caching!
2834

2935
def exist?(*args)
3036
nested_cache_provider.exist?(*args) || super
37+
rescue => e
38+
raise e unless ::ActiveRemote::Cached.default_options[:handle_cache_error]
39+
error_proc = ::ActiveRemote::Cached.default_options[:cache_error_proc]
40+
error_proc.call(e) if error_proc.respond_to?(:call)
41+
42+
false
3143
end
3244

3345
def fetch(name, options = {})
34-
fetch_value = nested_cache_provider.fetch(name, options) { super }
46+
fetch_value = read(name, options)
47+
if fetch_value.nil?
48+
fetch_value = super if block_given?
49+
write(name, fetch_value, options) if valid_fetched_value?(fetch_value, options)
50+
end
3551

3652
unless valid_fetched_value?(fetch_value, options)
3753
delete(name)
@@ -42,11 +58,23 @@ def fetch(name, options = {})
4258

4359
def read(*args)
4460
nested_cache_provider.read(*args) || super
61+
rescue => e
62+
raise e unless ::ActiveRemote::Cached.default_options[:handle_cache_error]
63+
error_proc = ::ActiveRemote::Cached.default_options[:cache_error_proc]
64+
error_proc.call(e) if error_proc.respond_to?(:call)
65+
66+
nil
4567
end
4668

4769
def write(*args)
4870
nested_cache_provider.write(*args)
4971
super
72+
rescue => e
73+
raise e unless ::ActiveRemote::Cached.default_options[:handle_cache_error]
74+
error_proc = ::ActiveRemote::Cached.default_options[:cache_error_proc]
75+
error_proc.call(e) if error_proc.respond_to?(:call)
76+
77+
nil
5078
end
5179

5280
private

lib/active_remote/cached/railtie.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,21 @@ class Railtie < ::Rails::Railtie
66
config.active_remote_cached = ::ActiveSupport::OrderedOptions.new
77

88
initializer "active_remote-cached.initialize_cache" do |app|
9+
config.active_remote_cached.cache_error_proc ||= nil
910
config.active_remote_cached.expires_in ||= 5.minutes
11+
config.active_remote_cached.handle_cache_error ||= false
1012
config.active_remote_cached.race_condition_ttl ||= 5.seconds
1113

12-
::ActiveRemote::Cached.cache(Rails.cache)
14+
::ActiveRemote::Cached.cache(::Rails.cache)
1315

1416
if config.active_remote_cached.enable_nested_caching
1517
::ActiveRemote::Cached.cache.enable_nested_caching!
1618
end
1719

1820
::ActiveRemote::Cached.default_options(
21+
:cache_error_proc => config.active_remote_cached.cache_error_proc,
1922
:expires_in => config.active_remote_cached.expires_in,
23+
:handle_cache_error => config.active_remote_cached.handle_cache_error,
2024
:race_condition_ttl => config.active_remote_cached.race_condition_ttl
2125
)
2226
end

0 commit comments

Comments
 (0)