cached_resource 7.2.0 → 8.0.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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +19 -25
- data/Gemfile +2 -0
- data/README.md +20 -19
- data/cached_resource.gemspec +1 -0
- data/gemfiles/7.1.gemfile +3 -0
- data/lib/cached_resource/cached_resource.rb +10 -0
- data/lib/cached_resource/caching.rb +11 -3
- data/lib/cached_resource/configuration.rb +9 -7
- data/lib/cached_resource/version.rb +1 -1
- data/spec/cached_resource/caching_spec.rb +23 -15
- metadata +23 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: af6263e0c63b68542a68f62371c79b057e8d9244eb4ab670cfa8956c7cdb1d54
|
|
4
|
+
data.tar.gz: 471295437c0567959f596cd4a8e13639dc670991632e99d01d1bbdea82123664
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 02ee32043c70de70d3befa042ad68c0de0b71e8abf0197e477e97a1489c51ed7eb726bc38a561dd29e34763184cea026275b6a9ff4b9e20ed2c8876f90d5944e
|
|
7
|
+
data.tar.gz: b652cbf1e7d42adaecf1639ac01c2489a75120bb2780bdb272fef5f2be9ad93fe339521d8e0337434cc98e6eb6234164274fa446710211c8eadb3a349435af15
|
data/.github/workflows/ruby.yml
CHANGED
|
@@ -19,31 +19,11 @@ jobs:
|
|
|
19
19
|
|
|
20
20
|
strategy:
|
|
21
21
|
matrix:
|
|
22
|
-
ruby-version: ['
|
|
23
|
-
rails-version: ['4.2', '5.0', '5.1', '6.0', '6.1', '7.0']
|
|
22
|
+
ruby-version: ['2.3', '2.4', '2.5', '2.6', '2.7', '3.0', '3.1', '3.2', '3.3']
|
|
23
|
+
rails-version: ['4.2', '5.0', '5.1', '6.0', '6.1', '7.0', '7.1']
|
|
24
24
|
exclude:
|
|
25
|
-
# Segmentation faults during tests, but should work?
|
|
26
|
-
- ruby-version: '2.2'
|
|
27
|
-
rails-version: '5.0'
|
|
28
|
-
- ruby-version: '2.2'
|
|
29
|
-
rails-version: '5.1'
|
|
30
|
-
# Too old
|
|
31
|
-
- ruby-version: '1.9'
|
|
32
|
-
rails-version: '5.0'
|
|
33
|
-
- ruby-version: '1.9'
|
|
34
|
-
rails-version: '5.1'
|
|
35
|
-
- ruby-version: '1.9'
|
|
36
|
-
rails-version: '6.0'
|
|
37
|
-
- ruby-version: '1.9'
|
|
38
|
-
rails-version: '6.1'
|
|
39
|
-
- ruby-version: '1.9'
|
|
40
|
-
rails-version: '7.0'
|
|
41
25
|
# activesupport (~> 6.0.0) was resolved to 6.0.6.1, which depends on ruby (>= 2.5.0)
|
|
42
26
|
# activesupport (~> 6.1.0) was resolved to 6.1.7.2, which depends on ruby (>= 2.5.0)
|
|
43
|
-
- ruby-version: '2.2'
|
|
44
|
-
rails-version: '6.0'
|
|
45
|
-
- ruby-version: '2.2'
|
|
46
|
-
rails-version: '6.1'
|
|
47
27
|
- ruby-version: '2.3'
|
|
48
28
|
rails-version: '6.0'
|
|
49
29
|
- ruby-version: '2.3'
|
|
@@ -53,8 +33,6 @@ jobs:
|
|
|
53
33
|
- ruby-version: '2.4'
|
|
54
34
|
rails-version: '6.1'
|
|
55
35
|
# activesupport (~> 7.0.0) was resolved to 7.0.4.2, which depends on Ruby (>= 2.7.0)
|
|
56
|
-
- ruby-version: '2.2'
|
|
57
|
-
rails-version: '7.0'
|
|
58
36
|
- ruby-version: '2.3'
|
|
59
37
|
rails-version: '7.0'
|
|
60
38
|
- ruby-version: '2.4'
|
|
@@ -87,9 +65,25 @@ jobs:
|
|
|
87
65
|
rails-version: '5.0'
|
|
88
66
|
- ruby-version: '3.2'
|
|
89
67
|
rails-version: '5.1'
|
|
68
|
+
# rails (~> 7.1.0) was resolved to 7.1.3.2, which depends on Ruby (>= 2.7.0)
|
|
69
|
+
- ruby-version: '2.3'
|
|
70
|
+
rails-version: '7.1'
|
|
71
|
+
- ruby-version: '2.4'
|
|
72
|
+
rails-version: '7.1'
|
|
73
|
+
- ruby-version: '2.5'
|
|
74
|
+
rails-version: '7.1'
|
|
75
|
+
- ruby-version: '2.6'
|
|
76
|
+
rails-version: '7.1'
|
|
77
|
+
# Because rails >= 4.0.0.beta1, < 5.0.5.rc1 depends on bundler >= 1.3.0, < 2.0
|
|
78
|
+
# and the current Bundler version (2.5.9) does not satisfy bundler >= 1.3.0, < 2.0,
|
|
79
|
+
# rails >= 4.0.0.beta1, < 5.0.5.rc1 cannot be used.
|
|
80
|
+
# So, because Gemfile depends on rails ~> 4.2.0,
|
|
81
|
+
# version solving has failed.
|
|
82
|
+
- ruby-version: '3.3'
|
|
83
|
+
rails-version: '4.2'
|
|
90
84
|
|
|
91
85
|
steps:
|
|
92
|
-
- uses: actions/checkout@
|
|
86
|
+
- uses: actions/checkout@v4
|
|
93
87
|
- name: Set up Ruby ${{ matrix.ruby-version }}
|
|
94
88
|
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
|
95
89
|
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
data/Gemfile
CHANGED
|
@@ -24,6 +24,8 @@ when "6.1"
|
|
|
24
24
|
eval_gemfile('../gemfiles/6.1.gemfile')
|
|
25
25
|
when "7.0"
|
|
26
26
|
eval_gemfile('../gemfiles/7.0.gemfile')
|
|
27
|
+
when "7.1"
|
|
28
|
+
eval_gemfile('../gemfiles/7.1.gemfile')
|
|
27
29
|
else
|
|
28
30
|
puts "\e[93mNo TEST_RAILS_VERSION present, letting dependency manager decide what's best.\e[0m" if ENV['DEBUG']
|
|
29
31
|
end
|
data/README.md
CHANGED
|
@@ -12,18 +12,17 @@ gem install cached_resource
|
|
|
12
12
|
|
|
13
13
|
CachedResource is designed to be framework agnostic, but will hook into Rails for caching and logging if available. CachedResource supports the following ActiveSupport/Rails (right) and Ruby (down) version combinations:
|
|
14
14
|
|
|
15
|
-
| | 🛤️ 4.2 | 🛤️ 5.0 | 🛤️ 5.1 | 🛤️ 6.0 | 🛤️ 6.1 | 🛤️ 7.0 |
|
|
16
|
-
|
|
17
|
-
| 💎
|
|
18
|
-
| 💎 2.
|
|
19
|
-
| 💎 2.
|
|
20
|
-
| 💎 2.
|
|
21
|
-
| 💎 2.
|
|
22
|
-
| 💎
|
|
23
|
-
| 💎
|
|
24
|
-
| 💎 3.
|
|
25
|
-
| 💎 3.
|
|
26
|
-
| 💎 3.2 | | | | ✅ | ✅ | ✅ |
|
|
15
|
+
| | 🛤️ 4.2 | 🛤️ 5.0 | 🛤️ 5.1 | 🛤️ 6.0 | 🛤️ 6.1 | 🛤️ 7.0 | 🛤️ 7.1 |
|
|
16
|
+
|-------|-----|-----|-----|-----|-----|-----|-----|
|
|
17
|
+
| 💎 2.3 | ✅ | ✅ | ✅ | | | | |
|
|
18
|
+
| 💎 2.4 | ✅ | ✅ | ✅ | | | | |
|
|
19
|
+
| 💎 2.5 | ✅ | ✅ | ✅ | ✅ | ✅ | | |
|
|
20
|
+
| 💎 2.6 | ✅ | ✅ | ✅ | ✅ | ✅ | |
|
|
21
|
+
| 💎 2.7 | | ✅ | ✅ | ✅ | ✅ | ✅ |✅ |
|
|
22
|
+
| 💎 3.0 | | | | ✅ | ✅ | ✅ | ✅ |
|
|
23
|
+
| 💎 3.1 | | | | ✅ | ✅ | ✅ | ✅ |
|
|
24
|
+
| 💎 3.2 | | | | ✅ | ✅ | ✅ | ✅ |
|
|
25
|
+
| 💎 3.3 | | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
27
26
|
|
|
28
27
|
## Limitations
|
|
29
28
|
|
|
@@ -55,15 +54,17 @@ end
|
|
|
55
54
|
CachedResource accepts the following options:
|
|
56
55
|
|
|
57
56
|
* `:enabled` Default: `true`
|
|
58
|
-
* `:
|
|
59
|
-
* `:
|
|
60
|
-
* `:ttl_randomization` Enable ttl randomization. Default: `false`
|
|
61
|
-
* `:ttl_randomization_scale` A Range from which a random value will be selected to scale the ttl. Default: `1..2`
|
|
62
|
-
* `:collection_synchronize` Use collections to generate cache entries for individuals. Update the existing cached principal collection when retrieving subsets of the principal collection or individuals. Default: `false`
|
|
57
|
+
* `:cache_collections` Set to false to always remake a request for collections. Default: `true`
|
|
58
|
+
* `:cache` The cache store that CacheResource should use. Default: The `Rails.cache` if available, or an `ActiveSupport::Cache::MemoryStore`
|
|
63
59
|
* `:collection_arguments` The arguments that identify the principal collection request. Default: `[:all]`
|
|
60
|
+
* `:collection_synchronize` Use collections to generate cache entries for individuals. Update the existing cached principal collection when retrieving subsets of the principal collection or individuals. Default: `false`
|
|
61
|
+
* `:concurrent_write` Set to true to make concurrent writes to cache after successful API response. Default: `false`
|
|
62
|
+
* Requires the [concurrent-ruby](https://rubygems.org/gems/concurrent-ruby) gem
|
|
64
63
|
* `:logger` The logger to which CachedResource messages should be written. Default: The `Rails.logger` if available, or an `ActiveSupport::Logger`
|
|
65
|
-
* `:
|
|
66
|
-
* `:
|
|
64
|
+
* `:race_condition_ttl` The race condition ttl, to prevent [dog pile effect](https://en.wikipedia.org/wiki/Cache_stampede) or [cache stampede](https://en.wikipedia.org/wiki/Cache_stampede). Default: 86400
|
|
65
|
+
* `:ttl_randomization_scale` A Range from which a random value will be selected to scale the ttl. Default: `1..2`
|
|
66
|
+
* `:ttl_randomization` Enable ttl randomization. Default: `false`
|
|
67
|
+
* `:ttl` The time in seconds until the cache should expire. Default: `604800`
|
|
67
68
|
|
|
68
69
|
You can set them like this:
|
|
69
70
|
|
data/cached_resource.gemspec
CHANGED
|
@@ -18,6 +18,16 @@ module CachedResource
|
|
|
18
18
|
# and establishing the necessary methods.
|
|
19
19
|
def setup_cached_resource!(options)
|
|
20
20
|
@cached_resource = CachedResource::Configuration.new(options)
|
|
21
|
+
if @cached_resource.concurrent_write
|
|
22
|
+
begin
|
|
23
|
+
send :require, 'concurrent/promise'
|
|
24
|
+
rescue LoadError
|
|
25
|
+
@cached_resource.logger.error(
|
|
26
|
+
"`concurrent_write` option is enabled, but `concurrent-ruby` is not an installed dependency"
|
|
27
|
+
)
|
|
28
|
+
raise
|
|
29
|
+
end
|
|
30
|
+
end
|
|
21
31
|
send :include, CachedResource::Caching
|
|
22
32
|
@cached_resource
|
|
23
33
|
end
|
|
@@ -45,7 +45,7 @@ module CachedResource
|
|
|
45
45
|
cache_collection_synchronize(object, *arguments) if cached_resource.collection_synchronize
|
|
46
46
|
return object if !cached_resource.cache_collections && is_any_collection?(*arguments)
|
|
47
47
|
cache_write(key, object, *arguments)
|
|
48
|
-
|
|
48
|
+
object
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
# If this is a pure, unadulterated "all" request
|
|
@@ -82,7 +82,7 @@ module CachedResource
|
|
|
82
82
|
# Avoid cache nil or [] objects
|
|
83
83
|
def should_cache?(object)
|
|
84
84
|
return false unless cached_resource.enabled
|
|
85
|
-
object.
|
|
85
|
+
object.present?
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
# Determine if the given arguments represent
|
|
@@ -110,7 +110,7 @@ module CachedResource
|
|
|
110
110
|
next restored unless respond_to?(:collection_parser)
|
|
111
111
|
collection_parser.new(restored).tap do |parser|
|
|
112
112
|
parser.resource_class = self
|
|
113
|
-
parser.original_params = json['original_params']
|
|
113
|
+
parser.original_params = json['original_params'].deep_symbolize_keys
|
|
114
114
|
end
|
|
115
115
|
else
|
|
116
116
|
full_dup(cache)
|
|
@@ -123,6 +123,14 @@ module CachedResource
|
|
|
123
123
|
|
|
124
124
|
# Write an entry to the cache for the given key and value.
|
|
125
125
|
def cache_write(key, object, *arguments)
|
|
126
|
+
if cached_resource.concurrent_write
|
|
127
|
+
Concurrent::Promise.execute { _cache_write(key, object, *arguments) } && true
|
|
128
|
+
else
|
|
129
|
+
_cache_write(key, object, *arguments)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def _cache_write(key, object, *arguments)
|
|
126
134
|
options = arguments[1] || {}
|
|
127
135
|
params = options[:params]
|
|
128
136
|
prefix_options, query_options = split_options(params)
|
|
@@ -24,18 +24,20 @@ module CachedResource
|
|
|
24
24
|
# :cache, default: Rails.cache or ActiveSupport::Cache::MemoryStore.new,
|
|
25
25
|
# :logger, default: Rails.logger or ActiveSupport::Logger.new(NilIO.new),
|
|
26
26
|
# :cache_collections, default: true
|
|
27
|
+
# :concurrent_write, default: false
|
|
27
28
|
def initialize(options={})
|
|
28
29
|
super({
|
|
29
30
|
:enabled => true,
|
|
31
|
+
:cache => defined?(Rails.cache) && Rails.cache || CACHE,
|
|
32
|
+
:cache_collections => true,
|
|
33
|
+
:collection_arguments => [:all],
|
|
34
|
+
:collection_synchronize => false,
|
|
35
|
+
:concurrent_write => false,
|
|
36
|
+
:logger => defined?(Rails.logger) && Rails.logger || LOGGER,
|
|
30
37
|
:race_condition_ttl => 86400,
|
|
31
38
|
:ttl => 604800,
|
|
32
39
|
:ttl_randomization => false,
|
|
33
|
-
:ttl_randomization_scale => 1..2
|
|
34
|
-
:collection_synchronize => false,
|
|
35
|
-
:collection_arguments => [:all],
|
|
36
|
-
:cache => defined?(Rails.cache) && Rails.cache || CACHE,
|
|
37
|
-
:logger => defined?(Rails.logger) && Rails.logger || LOGGER,
|
|
38
|
-
:cache_collections => true
|
|
40
|
+
:ttl_randomization_scale => 1..2
|
|
39
41
|
}.merge(options))
|
|
40
42
|
end
|
|
41
43
|
|
|
@@ -72,4 +74,4 @@ module CachedResource
|
|
|
72
74
|
end
|
|
73
75
|
|
|
74
76
|
end
|
|
75
|
-
end
|
|
77
|
+
end
|
|
@@ -66,19 +66,27 @@ describe CachedResource do
|
|
|
66
66
|
end
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
shared_examples "caching" do
|
|
70
|
+
it "should cache a response" do
|
|
71
|
+
result = Thing.find(1)
|
|
72
|
+
read_from_cache("thing/1").should == result
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "shouldn't cache nil response" do
|
|
76
|
+
Thing.find(:all, :params => { :name => '42' })
|
|
77
|
+
read_from_cache("thing/all/name/42").should == nil
|
|
78
|
+
end
|
|
73
79
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
80
|
+
it "shouldn't cache blank response" do
|
|
81
|
+
Thing.find(:all, :params => { :name => '43' })
|
|
82
|
+
read_from_cache("thing/all/name/43").should == nil
|
|
83
|
+
end
|
|
77
84
|
end
|
|
78
85
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
86
|
+
include_examples "caching"
|
|
87
|
+
|
|
88
|
+
context 'when concurrency is turned on' do
|
|
89
|
+
include_examples "caching"
|
|
82
90
|
end
|
|
83
91
|
|
|
84
92
|
it "should cache a response for a string primary key" do
|
|
@@ -234,12 +242,12 @@ describe CachedResource do
|
|
|
234
242
|
end
|
|
235
243
|
|
|
236
244
|
non_cached = Thing.where(name: 'ada')
|
|
237
|
-
non_cached.original_params.should == {
|
|
245
|
+
non_cached.original_params.should == { :name => 'ada' }
|
|
238
246
|
non_cached.map(&:id).should == @thing_collection.map { |h| h[:id]}
|
|
239
247
|
|
|
240
248
|
cached = read_from_cache('thing/all/{:params=>{:name=>"ada"}}')
|
|
241
249
|
cached.should be_instance_of(CustomCollection)
|
|
242
|
-
cached.original_params.should == {
|
|
250
|
+
cached.original_params.should == { :name => 'ada' }
|
|
243
251
|
cached.resource_class.should == Thing
|
|
244
252
|
cached.map(&:id).should == @thing_collection.map { |h| h[:id]}
|
|
245
253
|
|
|
@@ -249,11 +257,11 @@ describe CachedResource do
|
|
|
249
257
|
non_cached = cached.where(major: 'CS')
|
|
250
258
|
end
|
|
251
259
|
|
|
252
|
-
non_cached.original_params.should == {
|
|
260
|
+
non_cached.original_params.should == { :name => 'ada', :major => 'CS' }
|
|
253
261
|
non_cached.resource_class.should == Thing
|
|
254
262
|
non_cached.map(&:id).should == @thing_collection2.map { |h| h[:id]}
|
|
255
|
-
cached = read_from_cache('thing/all/{:params=>{
|
|
256
|
-
cached.original_params.should == {
|
|
263
|
+
cached = read_from_cache('thing/all/{:params=>{:name=>"ada",:major=>"cs"}}')
|
|
264
|
+
cached.original_params.should == { :name => 'ada', :major => 'CS' }
|
|
257
265
|
cached.resource_class.should == Thing
|
|
258
266
|
cached.map(&:id).should == @thing_collection2.map { |h| h[:id]}
|
|
259
267
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cached_resource
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 8.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Morgan Brown
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-
|
|
11
|
+
date: 2024-05-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activeresource
|
|
@@ -80,6 +80,26 @@ dependencies:
|
|
|
80
80
|
- - ">="
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: '0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: concurrent-ruby
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '1.2'
|
|
90
|
+
- - ">="
|
|
91
|
+
- !ruby/object:Gem::Version
|
|
92
|
+
version: 1.2.3
|
|
93
|
+
type: :development
|
|
94
|
+
prerelease: false
|
|
95
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
96
|
+
requirements:
|
|
97
|
+
- - "~>"
|
|
98
|
+
- !ruby/object:Gem::Version
|
|
99
|
+
version: '1.2'
|
|
100
|
+
- - ">="
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: 1.2.3
|
|
83
103
|
description: Enables request-based caching for ActiveResource
|
|
84
104
|
email: cached_resource@email.mhgbrown.is
|
|
85
105
|
executables: []
|
|
@@ -101,6 +121,7 @@ files:
|
|
|
101
121
|
- gemfiles/6.0.gemfile
|
|
102
122
|
- gemfiles/6.1.gemfile
|
|
103
123
|
- gemfiles/7.0.gemfile
|
|
124
|
+
- gemfiles/7.1.gemfile
|
|
104
125
|
- lib/cached_resource.rb
|
|
105
126
|
- lib/cached_resource/cached_resource.rb
|
|
106
127
|
- lib/cached_resource/caching.rb
|