cache_keeper 0.1.2 → 0.2.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 +4 -4
- data/Gemfile +1 -0
- data/Gemfile.lock +3 -1
- data/README.md +24 -3
- data/app/jobs/cache_keeper/refresh_all_job.rb +11 -0
- data/app/models/cache_keeper/cached_method/refreshable.rb +3 -1
- data/app/models/cache_keeper/cached_method.rb +4 -0
- data/cache_keeper.gemspec +1 -1
- data/lib/cache_keeper/configuration.rb +18 -2
- data/lib/cache_keeper/cron/good_job_adapter.rb +10 -0
- data/lib/cache_keeper/cron.rb +7 -0
- data/lib/cache_keeper/engine.rb +8 -1
- data/lib/cache_keeper/manager.rb +26 -12
- data/lib/cache_keeper/store.rb +15 -0
- data/lib/cache_keeper/version.rb +1 -1
- data/lib/cache_keeper.rb +2 -0
- data/test/dummy/app/models/recording.rb +4 -0
- data/test/manager_test.rb +17 -0
- data/test/store_test.rb +19 -0
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d50a51737d307549be39ed49fb7edcfe391a270c0b55d25b52e70092276c548c
|
4
|
+
data.tar.gz: 5f2d9f844f4eb18bd41eb27a51558d4dd4aec13672abaf13cdcf2598cdfe8263
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '0519ed2a41f0c66ffcd0e8911f22d87f7e62b4b0fee2d3c1d1f9f9c567f9ebcebfa196b7253eb89b1534e04f5dbec873c94715ebc39fcb0e7836d4c5927b84d8'
|
7
|
+
data.tar.gz: 6b341290d842a7c6ec3c04170989428ea52bbfbd5a6f916a649aa0617326fb42766111f4dedbfcf714b86d403d26f3f5b57635c4cc3e9a34630ab130111da278
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cache_keeper (0.1
|
4
|
+
cache_keeper (0.2.1)
|
5
5
|
rails (>= 6.1.0)
|
6
6
|
|
7
7
|
GEM
|
@@ -83,6 +83,7 @@ GEM
|
|
83
83
|
base64 (0.1.1)
|
84
84
|
bigdecimal (3.1.4)
|
85
85
|
builder (3.2.4)
|
86
|
+
byebug (11.1.3)
|
86
87
|
concurrent-ruby (1.2.2)
|
87
88
|
connection_pool (2.4.1)
|
88
89
|
crass (1.0.6)
|
@@ -188,6 +189,7 @@ PLATFORMS
|
|
188
189
|
x86_64-linux
|
189
190
|
|
190
191
|
DEPENDENCIES
|
192
|
+
byebug
|
191
193
|
cache_keeper!
|
192
194
|
rails (>= 6.1)
|
193
195
|
rake
|
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
<br>
|
4
4
|
</h1>
|
5
5
|
|
6
|
-
<h3 align="center">
|
6
|
+
<h3 align="center">Have your cached methods refreshed asynchronously and automatically.</h3>
|
7
7
|
|
8
8
|
<p align="center">
|
9
9
|
<img alt="Build" src="https://img.shields.io/github/actions/workflow/status/martinzamuner/cache_keeper/ci.yml?branch=main">
|
@@ -12,7 +12,7 @@
|
|
12
12
|
<img alt="License" src="https://img.shields.io/github/license/martinzamuner/cache_keeper">
|
13
13
|
</p>
|
14
14
|
|
15
|
-
CacheKeeper allows you to mark any method to be kept fresh in your
|
15
|
+
CacheKeeper is a Rails gem that allows you to mark any method to be kept fresh in your cache. It uses ActiveJob to refresh the cache in the background, either on demand or periodically.
|
16
16
|
|
17
17
|
|
18
18
|
## Installation
|
@@ -33,10 +33,22 @@ caches :slow_method, :really_slow_method, expires_in: 1.hour
|
|
33
33
|
caches :incredibly_slow_method, expires_in: 2.hours, must_revalidate: true
|
34
34
|
```
|
35
35
|
|
36
|
-
It
|
36
|
+
It's automatically available in your ActiveRecord models and in your controllers. You can also use it in any other class by including `CacheKeeper::Caching`.
|
37
37
|
|
38
38
|
By default, it will immediately run the method call if it hasn't been cached before. The next time it is called, it will return the cached value if it hasn't expired yet. If it has expired, it will enqueue a job to refresh the cache in the background and return the stale value in the meantime. You can avoid returning stale values by setting `must_revalidate: true` in the options.
|
39
39
|
|
40
|
+
It's important to note that it will only work with methods that don't take any arguments.
|
41
|
+
|
42
|
+
### Autorefresh
|
43
|
+
|
44
|
+
You can tell CacheKeeper to automatically refresh the cache after a certain amount of time by setting the `autorefresh` option:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
caches :i_cant_even, expires_in: 2.hours, autorefresh: true
|
48
|
+
```
|
49
|
+
|
50
|
+
This works by running a job in cron mode that will periodically check for stale entries and enqueue a job to refresh them. You need to specify an adapter as explained in the configuration section below.
|
51
|
+
|
40
52
|
|
41
53
|
## Configuration
|
42
54
|
|
@@ -51,6 +63,15 @@ Rails.application.configure do
|
|
51
63
|
# The queue to use for the refresh jobs.
|
52
64
|
# Default: nil (uses the default queue)
|
53
65
|
config.cache_keeper.queues.refresh = :low_priority
|
66
|
+
|
67
|
+
# The adapter to use for the autorefresh cron job.
|
68
|
+
# Options: :good_job
|
69
|
+
# Default: nil
|
70
|
+
config.cache_keeper.cron.adapter = :good_job
|
71
|
+
|
72
|
+
# The cron expression to use for the autorefresh cron job.
|
73
|
+
# Default: "*/15 * * * *" (every 15 minutes)
|
74
|
+
config.cache_keeper.cron.expression = "0 * * * *"
|
54
75
|
end
|
55
76
|
```
|
56
77
|
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class CacheKeeper::RefreshAllJob < CacheKeeper::BaseJob
|
2
|
+
queue_as { CacheKeeper.configuration.queues[:refresh] }
|
3
|
+
|
4
|
+
def perform
|
5
|
+
CacheKeeper.manager.cached_methods.autorefreshed.each do |cached_method|
|
6
|
+
next unless cached_method.stale?
|
7
|
+
|
8
|
+
cached_method.refresh_later
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/cache_keeper.gemspec
CHANGED
@@ -5,7 +5,7 @@ Gem::Specification.new do |s|
|
|
5
5
|
s.version = CacheKeeper::VERSION
|
6
6
|
s.authors = ["Martin Zamuner"]
|
7
7
|
s.email = "martinzamuner@gmail.com"
|
8
|
-
s.summary = "
|
8
|
+
s.summary = "Have your cached methods refreshed asynchronously and automatically"
|
9
9
|
s.homepage = "https://github.com/martinzamuner/cache_keeper"
|
10
10
|
s.license = "MIT"
|
11
11
|
|
@@ -2,15 +2,31 @@ module CacheKeeper
|
|
2
2
|
class Configuration
|
3
3
|
DEFAULT_MUST_REVALIDATE = false
|
4
4
|
DEFAULT_QUEUES = {}
|
5
|
+
DEFAULT_CRON_EXPRESSION = "*/15 * * * *" # Every 15 minutes, every day
|
5
6
|
|
6
7
|
def must_revalidate
|
7
|
-
return rails_config
|
8
|
+
return rails_config.must_revalidate unless rails_config.must_revalidate.nil?
|
8
9
|
|
9
10
|
DEFAULT_MUST_REVALIDATE
|
10
11
|
end
|
11
12
|
|
12
13
|
def queues
|
13
|
-
rails_config
|
14
|
+
rails_config.queues || DEFAULT_QUEUES
|
15
|
+
end
|
16
|
+
|
17
|
+
def cron_adapter
|
18
|
+
return if rails_config.cron.adapter.nil?
|
19
|
+
|
20
|
+
case rails_config.cron.adapter
|
21
|
+
when :good_job
|
22
|
+
CacheKeeper::Cron::GoodJobAdapter
|
23
|
+
else
|
24
|
+
raise "Unknown cron adapter: #{rails_config.cron.adapter}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def cron_expression
|
29
|
+
rails_config.cron.expression || DEFAULT_CRON_EXPRESSION
|
14
30
|
end
|
15
31
|
|
16
32
|
private
|
data/lib/cache_keeper/engine.rb
CHANGED
@@ -3,7 +3,8 @@ module CacheKeeper
|
|
3
3
|
isolate_namespace CacheKeeper
|
4
4
|
|
5
5
|
config.cache_keeper = ActiveSupport::OrderedOptions.new
|
6
|
-
config.cache_keeper.queues = ActiveSupport::
|
6
|
+
config.cache_keeper.queues = ActiveSupport::OrderedOptions.new
|
7
|
+
config.cache_keeper.cron = ActiveSupport::OrderedOptions.new
|
7
8
|
|
8
9
|
config.eager_load_namespaces << CacheKeeper
|
9
10
|
config.autoload_once_paths = %W(
|
@@ -18,6 +19,12 @@ module CacheKeeper
|
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
22
|
+
initializer "cache_keeper.cron_adapter" do |app|
|
23
|
+
config.to_prepare do
|
24
|
+
CacheKeeper.configuration.cron_adapter&.setup
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
21
28
|
initializer "cache_keeper.caching_methods" do |app|
|
22
29
|
ActiveSupport.on_load :action_controller do
|
23
30
|
ActionController::Base.send :include, CacheKeeper::Caching
|
data/lib/cache_keeper/manager.rb
CHANGED
@@ -3,32 +3,34 @@ module CacheKeeper
|
|
3
3
|
attr_accessor :cached_methods
|
4
4
|
|
5
5
|
def initialize
|
6
|
-
self.cached_methods =
|
7
|
-
end
|
8
|
-
|
9
|
-
def find(klass, method_name)
|
10
|
-
cached_methods.find do |cached_method|
|
11
|
-
cached_method.klass == klass && cached_method.method_name == method_name
|
12
|
-
end
|
6
|
+
self.cached_methods = CacheKeeper::Store.new
|
13
7
|
end
|
14
8
|
|
15
9
|
def handled?(klass, method_name)
|
16
|
-
|
10
|
+
cached_methods.find_by(klass, method_name).present?
|
17
11
|
end
|
18
12
|
|
19
13
|
def handle(klass, method_name, options)
|
20
14
|
CacheKeeper::CachedMethod.new(klass, method_name, options).tap do |cached_method|
|
15
|
+
if unsupported_options?(cached_method)
|
16
|
+
raise "You're trying to autorefresh an ActiveRecord model, which we don't currently support."
|
17
|
+
end
|
18
|
+
|
21
19
|
cached_methods << cached_method
|
22
20
|
end
|
23
21
|
end
|
24
22
|
|
25
23
|
def activate_if_handling(klass, method_name)
|
26
|
-
cached_method =
|
24
|
+
cached_method = cached_methods.find_by(klass, method_name) or return
|
27
25
|
|
28
|
-
|
26
|
+
if requires_activation?(cached_method)
|
27
|
+
if unsupported_arity?(cached_method)
|
28
|
+
raise "You're trying to cache a method with parameters, which we don't currently support."
|
29
|
+
end
|
29
30
|
|
30
|
-
|
31
|
-
|
31
|
+
CacheKeeper::ReplaceMethod.replace(cached_method) do
|
32
|
+
cached_method.call(self)
|
33
|
+
end
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
@@ -40,5 +42,17 @@ module CacheKeeper
|
|
40
42
|
|
41
43
|
true
|
42
44
|
end
|
45
|
+
|
46
|
+
def unsupported_options?(cached_method)
|
47
|
+
cached_method.klass < ActiveRecord::Base && cached_method.options[:autorefresh].present?
|
48
|
+
end
|
49
|
+
|
50
|
+
def unsupported_arity?(cached_method)
|
51
|
+
original_method =
|
52
|
+
cached_method.klass.instance_method(cached_method.method_name) ||
|
53
|
+
cached_method.klass.privateinstance_method(cached_method.method_name)
|
54
|
+
|
55
|
+
original_method.arity.nonzero?
|
56
|
+
end
|
43
57
|
end
|
44
58
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module CacheKeeper
|
2
|
+
class Store < Array
|
3
|
+
def find_by(klass, method_name)
|
4
|
+
find do |cached_method|
|
5
|
+
cached_method.klass == klass && cached_method.method_name == method_name
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def autorefreshed
|
10
|
+
select do |cached_method|
|
11
|
+
cached_method.options[:autorefresh].present?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/cache_keeper/version.rb
CHANGED
data/lib/cache_keeper.rb
CHANGED
data/test/manager_test.rb
CHANGED
@@ -8,4 +8,21 @@ class CacheKeeper::ManagerTest < ActiveSupport::TestCase
|
|
8
8
|
assert_equal 1, CacheKeeper.manager.cached_methods.count
|
9
9
|
assert_equal :slow_method, CacheKeeper.manager.cached_methods.first.method_name
|
10
10
|
end
|
11
|
+
|
12
|
+
test "doesn't allow to autorefresh ActiveRecord models" do
|
13
|
+
manager = CacheKeeper::Manager.new
|
14
|
+
|
15
|
+
assert_raises RuntimeError do
|
16
|
+
manager.handle Recording, :slow_method, autorefresh: true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
test "doesn't allow to activate methods with parameters" do
|
21
|
+
manager = CacheKeeper::Manager.new
|
22
|
+
manager.handle Recording, :unsupported_method, {}
|
23
|
+
|
24
|
+
assert_raises RuntimeError do
|
25
|
+
manager.activate_if_handling Recording, :unsupported_method
|
26
|
+
end
|
27
|
+
end
|
11
28
|
end
|
data/test/store_test.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class CacheKeeper::StoreTest < ActiveSupport::TestCase
|
4
|
+
test "#find_by returns only the one with the requested parameters" do
|
5
|
+
cached_method = CacheKeeper::CachedMethod.new(String, :slow_method, {})
|
6
|
+
autorefreshed_cached_method = CacheKeeper::CachedMethod.new(String, :really_slow_method, { autorefresh: true })
|
7
|
+
store = CacheKeeper::Store.new([cached_method, autorefreshed_cached_method])
|
8
|
+
|
9
|
+
assert_equal autorefreshed_cached_method, store.find_by(String, :really_slow_method)
|
10
|
+
end
|
11
|
+
|
12
|
+
test "#autorefreshed returns only the ones with the correct option" do
|
13
|
+
cached_method = CacheKeeper::CachedMethod.new(String, :slow_method, {})
|
14
|
+
autorefreshed_cached_method = CacheKeeper::CachedMethod.new(String, :really_slow_method, { autorefresh: true })
|
15
|
+
store = CacheKeeper::Store.new([cached_method, autorefreshed_cached_method])
|
16
|
+
|
17
|
+
assert_equal [autorefreshed_cached_method], store.autorefreshed
|
18
|
+
end
|
19
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cache_keeper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Zamuner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-10-
|
11
|
+
date: 2023-10-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -37,6 +37,7 @@ files:
|
|
37
37
|
- MIT-LICENSE
|
38
38
|
- README.md
|
39
39
|
- app/jobs/cache_keeper/base_job.rb
|
40
|
+
- app/jobs/cache_keeper/refresh_all_job.rb
|
40
41
|
- app/jobs/cache_keeper/refresh_job.rb
|
41
42
|
- app/models/cache_keeper/cached_method.rb
|
42
43
|
- app/models/cache_keeper/cached_method/refreshable.rb
|
@@ -49,9 +50,12 @@ files:
|
|
49
50
|
- lib/cache_keeper.rb
|
50
51
|
- lib/cache_keeper/caching.rb
|
51
52
|
- lib/cache_keeper/configuration.rb
|
53
|
+
- lib/cache_keeper/cron.rb
|
54
|
+
- lib/cache_keeper/cron/good_job_adapter.rb
|
52
55
|
- lib/cache_keeper/engine.rb
|
53
56
|
- lib/cache_keeper/manager.rb
|
54
57
|
- lib/cache_keeper/replace_method.rb
|
58
|
+
- lib/cache_keeper/store.rb
|
55
59
|
- lib/cache_keeper/version.rb
|
56
60
|
- test/cache_helper.rb
|
57
61
|
- test/dummy/Rakefile
|
@@ -128,6 +132,7 @@ files:
|
|
128
132
|
- test/models/cached_method_test.rb
|
129
133
|
- test/serializers/cached_method_serializer_test.rb
|
130
134
|
- test/serializers/whatever_serializer_test.rb
|
135
|
+
- test/store_test.rb
|
131
136
|
- test/test_helper.rb
|
132
137
|
homepage: https://github.com/martinzamuner/cache_keeper
|
133
138
|
licenses:
|
@@ -151,7 +156,7 @@ requirements: []
|
|
151
156
|
rubygems_version: 3.4.10
|
152
157
|
signing_key:
|
153
158
|
specification_version: 4
|
154
|
-
summary:
|
159
|
+
summary: Have your cached methods refreshed asynchronously and automatically
|
155
160
|
test_files:
|
156
161
|
- test/cache_helper.rb
|
157
162
|
- test/dummy/Rakefile
|
@@ -228,4 +233,5 @@ test_files:
|
|
228
233
|
- test/models/cached_method_test.rb
|
229
234
|
- test/serializers/cached_method_serializer_test.rb
|
230
235
|
- test/serializers/whatever_serializer_test.rb
|
236
|
+
- test/store_test.rb
|
231
237
|
- test/test_helper.rb
|