cache_keeper 0.2.0 → 0.3.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/Gemfile.lock +1 -1
- data/README.md +12 -13
- data/app/jobs/cache_keeper/base_job.rb +8 -4
- data/app/jobs/cache_keeper/refresh_job.rb +2 -2
- data/app/models/cache_keeper/cached_method/refreshable.rb +4 -6
- data/app/models/cache_keeper/cached_method/serializable_target.rb +18 -0
- data/app/models/cache_keeper/cached_method.rb +5 -4
- data/app/serializers/cache_keeper/marshal_serializer.rb +9 -0
- data/app/serializers/cache_keeper/new_instance_serializer.rb +9 -0
- data/lib/cache_keeper/configuration.rb +0 -16
- data/lib/cache_keeper/engine.rb +2 -14
- data/lib/cache_keeper/manager.rb +1 -1
- data/lib/cache_keeper/version.rb +1 -1
- data/lib/cache_keeper.rb +0 -1
- data/test/dummy/app/models/recording.rb +0 -2
- data/test/engine_test.rb +6 -2
- data/test/jobs/refresh_job_test.rb +14 -0
- data/test/models/cached_method/refreshable_test.rb +14 -0
- data/test/models/cached_method/serializable_target_test.rb +24 -0
- data/test/serializers/marshal_serializer_test.rb +24 -0
- data/test/serializers/{whatever_serializer_test.rb → new_instance_serializer_test.rb} +2 -6
- metadata +14 -7
- data/app/jobs/cache_keeper/refresh_all_job.rb +0 -11
- data/app/serializers/cache_keeper/whatever_serializer.rb +0 -15
- data/lib/cache_keeper/cron/good_job_adapter.rb +0 -10
- data/lib/cache_keeper/cron.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 167f1cc0d9fdfca15b5882a90dde733b9d74b65f3adfad47f71ef34606b6e9d0
|
4
|
+
data.tar.gz: 278285596e0e0bdcbab9a687c07244c0c2f57d19e588b275ccb3e3281a8f3f78
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 62d8e87244040101cb4f345c1e11a6b857c23bd7d7074877e0358d18e44c8acf7b76182ce0a922fa2998699ea74ede71484430c4f701cd12978710e7420b3022
|
7
|
+
data.tar.gz: 72a3207e7df9c92dcaf5764ba3055bed5cba3e943c406f824e6087d741c245301b7b11f05c00091cd8c77ed6a5739e31a843134f08d6856f9d677ee54a2f645d
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -39,15 +39,23 @@ By default, it will immediately run the method call if it hasn't been cached bef
|
|
39
39
|
|
40
40
|
It's important to note that it will only work with methods that don't take any arguments.
|
41
41
|
|
42
|
-
###
|
42
|
+
### Serialization
|
43
43
|
|
44
|
-
|
44
|
+
CacheKeeper needs to pass the instance on which the cached method is called along to the refresh job. As any other job argument, ActiveJob requires it to be serializable. ActiveRecord instances are serializable by default, but controllers, POROs and other classes are not. CacheKeeper provides a `serializer` option that will work in most cases:
|
45
45
|
|
46
46
|
```ruby
|
47
|
-
|
47
|
+
class Example
|
48
|
+
# Generate a new instance using an empty initializer (Example.new)
|
49
|
+
# Useful for controllers and for POROs with no arguments
|
50
|
+
caches :slow_method, serializer: :new_instance
|
51
|
+
|
52
|
+
# Replicate the old instance using Marshal.dump and Marshal.load
|
53
|
+
# Useful in most other cases, but make sure the dump is not too big
|
54
|
+
caches :slow_method, serializer: :marshal
|
55
|
+
end
|
48
56
|
```
|
49
57
|
|
50
|
-
|
58
|
+
If those options don't work for you, you can always [write custom serializer](https://guides.rubyonrails.org/active_job_basics.html#serializers) for your classes.
|
51
59
|
|
52
60
|
|
53
61
|
## Configuration
|
@@ -63,15 +71,6 @@ Rails.application.configure do
|
|
63
71
|
# The queue to use for the refresh jobs.
|
64
72
|
# Default: nil (uses the default queue)
|
65
73
|
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 * * * *"
|
75
74
|
end
|
76
75
|
```
|
77
76
|
|
@@ -3,14 +3,18 @@ class CacheKeeper::BaseJob < ActiveJob::Base
|
|
3
3
|
|
4
4
|
private
|
5
5
|
|
6
|
-
# Monkey patch ActiveJob::Core#serialize_arguments to use
|
7
|
-
# in case
|
6
|
+
# Monkey patch ActiveJob::Core#serialize_arguments to use our custom serializers
|
7
|
+
# in case the `serializer` option is present. I'm doing it this way because I don't
|
8
8
|
# want to register the serializer as it would affect the whole application.
|
9
9
|
def serialize_arguments(arguments)
|
10
10
|
arguments.map do |argument|
|
11
11
|
ActiveJob::Arguments.send :serialize_argument, argument
|
12
|
-
rescue ActiveJob::SerializationError
|
13
|
-
|
12
|
+
rescue ActiveJob::SerializationError => e
|
13
|
+
if arguments.first.serialize_target?
|
14
|
+
arguments.first.serialize_target argument
|
15
|
+
else
|
16
|
+
raise e
|
17
|
+
end
|
14
18
|
end
|
15
19
|
end
|
16
20
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class CacheKeeper::RefreshJob < CacheKeeper::BaseJob
|
2
2
|
queue_as { CacheKeeper.configuration.queues[:refresh] }
|
3
3
|
|
4
|
-
def perform(cached_method,
|
5
|
-
cached_method.refresh
|
4
|
+
def perform(cached_method, target)
|
5
|
+
cached_method.refresh target
|
6
6
|
end
|
7
7
|
end
|
@@ -1,13 +1,11 @@
|
|
1
1
|
module CacheKeeper::CachedMethod::Refreshable
|
2
|
-
def refresh(
|
2
|
+
def refresh(target)
|
3
3
|
Rails.cache.fetch(cache_key, expires_in: expires_in) do
|
4
|
-
|
4
|
+
target.send alias_for_original_method
|
5
5
|
end
|
6
6
|
end
|
7
7
|
|
8
|
-
def refresh_later(
|
9
|
-
|
10
|
-
|
11
|
-
CacheKeeper::RefreshJob.perform_later self, instance
|
8
|
+
def refresh_later(target)
|
9
|
+
CacheKeeper::RefreshJob.perform_later self, target
|
12
10
|
end
|
13
11
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module CacheKeeper::CachedMethod::SerializableTarget
|
2
|
+
def serialize_target?
|
3
|
+
options[:serializer].present?
|
4
|
+
end
|
5
|
+
|
6
|
+
def serialize_target(target)
|
7
|
+
case options[:serializer]
|
8
|
+
when :new_instance
|
9
|
+
CacheKeeper::NewInstanceSerializer.serialize target
|
10
|
+
when :marshal
|
11
|
+
CacheKeeper::MarshalSerializer.serialize target
|
12
|
+
else
|
13
|
+
raise "Unknown serializer: #{options[:serializer]}"
|
14
|
+
end
|
15
|
+
rescue StandardError => e
|
16
|
+
raise "Error serializing target using #{options[:serializer]}: #{e}"
|
17
|
+
end
|
18
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
class CacheKeeper::CachedMethod
|
2
2
|
include Refreshable
|
3
|
+
include SerializableTarget
|
3
4
|
|
4
5
|
attr_accessor :klass, :method_name, :options
|
5
6
|
|
@@ -17,14 +18,14 @@ class CacheKeeper::CachedMethod
|
|
17
18
|
cache_entry.blank? || cache_entry.expired?
|
18
19
|
end
|
19
20
|
|
20
|
-
def call(
|
21
|
+
def call(target)
|
21
22
|
if cache_entry.blank?
|
22
|
-
refresh
|
23
|
+
refresh target
|
23
24
|
elsif cache_entry.expired?
|
24
25
|
if must_revalidate?
|
25
|
-
refresh
|
26
|
+
refresh target
|
26
27
|
else
|
27
|
-
refresh_later
|
28
|
+
refresh_later target
|
28
29
|
|
29
30
|
cache_entry.value
|
30
31
|
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class CacheKeeper::MarshalSerializer < ActiveJob::Serializers::ObjectSerializer
|
2
|
+
def serialize(target)
|
3
|
+
super("dump" => Marshal.dump(target).force_encoding("ISO-8859-1").encode("UTF-8"))
|
4
|
+
end
|
5
|
+
|
6
|
+
def deserialize(json)
|
7
|
+
Marshal.load(json["dump"].encode("ISO-8859-1").force_encoding("ASCII-8BIT"))
|
8
|
+
end
|
9
|
+
end
|
@@ -2,7 +2,6 @@ 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
|
6
5
|
|
7
6
|
def must_revalidate
|
8
7
|
return rails_config.must_revalidate unless rails_config.must_revalidate.nil?
|
@@ -14,21 +13,6 @@ module CacheKeeper
|
|
14
13
|
rails_config.queues || DEFAULT_QUEUES
|
15
14
|
end
|
16
15
|
|
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
|
30
|
-
end
|
31
|
-
|
32
16
|
private
|
33
17
|
|
34
18
|
def rails_config
|
data/lib/cache_keeper/engine.rb
CHANGED
@@ -2,16 +2,10 @@ module CacheKeeper
|
|
2
2
|
class Engine < ::Rails::Engine
|
3
3
|
isolate_namespace CacheKeeper
|
4
4
|
|
5
|
+
config.eager_load_namespaces << CacheKeeper
|
6
|
+
|
5
7
|
config.cache_keeper = ActiveSupport::OrderedOptions.new
|
6
8
|
config.cache_keeper.queues = ActiveSupport::OrderedOptions.new
|
7
|
-
config.cache_keeper.cron = ActiveSupport::OrderedOptions.new
|
8
|
-
|
9
|
-
config.eager_load_namespaces << CacheKeeper
|
10
|
-
config.autoload_once_paths = %W(
|
11
|
-
#{root}/app/jobs
|
12
|
-
#{root}/app/models
|
13
|
-
#{root}/app/serializers
|
14
|
-
)
|
15
9
|
|
16
10
|
initializer "cache_keeper.active_job_serializer" do |app|
|
17
11
|
config.to_prepare do
|
@@ -19,12 +13,6 @@ module CacheKeeper
|
|
19
13
|
end
|
20
14
|
end
|
21
15
|
|
22
|
-
initializer "cache_keeper.cron_adapter" do |app|
|
23
|
-
config.to_prepare do
|
24
|
-
CacheKeeper.configuration.cron_adapter&.setup
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
16
|
initializer "cache_keeper.caching_methods" do |app|
|
29
17
|
ActiveSupport.on_load :action_controller do
|
30
18
|
ActionController::Base.send :include, CacheKeeper::Caching
|
data/lib/cache_keeper/manager.rb
CHANGED
data/lib/cache_keeper/version.rb
CHANGED
data/lib/cache_keeper.rb
CHANGED
data/test/engine_test.rb
CHANGED
@@ -5,7 +5,11 @@ class CacheKeeper::EngineTest < ActiveSupport::TestCase
|
|
5
5
|
assert_includes Rails.application.config.active_job.custom_serializers, CacheKeeper::CachedMethodSerializer
|
6
6
|
end
|
7
7
|
|
8
|
-
test "doesn't register the ActiveJob serializer
|
9
|
-
assert_not_includes Rails.application.config.active_job.custom_serializers, CacheKeeper::
|
8
|
+
test "doesn't register the ActiveJob new_instance serializer" do
|
9
|
+
assert_not_includes Rails.application.config.active_job.custom_serializers, CacheKeeper::NewInstanceSerializer
|
10
|
+
end
|
11
|
+
|
12
|
+
test "doesn't register the ActiveJob marshal serializer" do
|
13
|
+
assert_not_includes Rails.application.config.active_job.custom_serializers, CacheKeeper::MarshalSerializer
|
10
14
|
end
|
11
15
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class CacheKeeper::RefreshJobTest < ActiveSupport::TestCase
|
4
|
+
include ActiveJob::TestHelper
|
5
|
+
|
6
|
+
test "calls #refresh" do
|
7
|
+
recording = Recording.create(number: 5)
|
8
|
+
cached_method = CacheKeeper.manager.cached_methods.first
|
9
|
+
|
10
|
+
assert_performed_with(queue: :default) do
|
11
|
+
CacheKeeper::RefreshJob.perform_later cached_method, recording
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class CacheKeeper::CachedMethod::RefreshableTest < ActiveSupport::TestCase
|
4
|
+
include ActiveJob::TestHelper
|
5
|
+
|
6
|
+
test "#refresh_later enqueues a refresh job" do
|
7
|
+
recording = Recording.create(number: 5)
|
8
|
+
cached_method = CacheKeeper.manager.cached_methods.first
|
9
|
+
|
10
|
+
assert_enqueued_with(job: CacheKeeper::RefreshJob, queue: :default) do
|
11
|
+
cached_method.refresh_later recording
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class CacheKeeper::CachedMethod::SerializableTargetTest < ActiveSupport::TestCase
|
4
|
+
test "#serialize_target doesn't allow unknown serializers" do
|
5
|
+
recording = Recording.new(number: 5)
|
6
|
+
cached_method = CacheKeeper::CachedMethod.new(Recording, :another_method, serializer: :unknown_serializer)
|
7
|
+
|
8
|
+
error = assert_raises RuntimeError do
|
9
|
+
cached_method.serialize_target(recording)
|
10
|
+
end
|
11
|
+
|
12
|
+
assert_includes error.message, "Unknown serializer: unknown_serializer"
|
13
|
+
end
|
14
|
+
|
15
|
+
test "#serialize_target raises an error if unable to serialize" do
|
16
|
+
cached_method = CacheKeeper::CachedMethod.new(Recording, :another_method, serializer: :marshal)
|
17
|
+
|
18
|
+
error = assert_raises RuntimeError do
|
19
|
+
cached_method.serialize_target(Proc.new {})
|
20
|
+
end
|
21
|
+
|
22
|
+
assert_includes error.message, "Error serializing target using marshal:"
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class CacheKeeper::MarshalSerializerTest < ActiveSupport::TestCase
|
4
|
+
test "serializes the marshal dump" do
|
5
|
+
target = Recording.new
|
6
|
+
serialized = serializer.serialize(target)
|
7
|
+
|
8
|
+
assert_equal serialized["dump"], Marshal.dump(target).force_encoding("ISO-8859-1").encode("UTF-8")
|
9
|
+
end
|
10
|
+
|
11
|
+
test "deserializes the marshal dump" do
|
12
|
+
target = Recording.new
|
13
|
+
serialized = serializer.serialize(target)
|
14
|
+
deserialized = serializer.deserialize(serialized)
|
15
|
+
|
16
|
+
assert_equal Recording, deserialized.class
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def serializer
|
22
|
+
CacheKeeper::MarshalSerializer
|
23
|
+
end
|
24
|
+
end
|
@@ -1,10 +1,6 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
|
-
class CacheKeeper::
|
4
|
-
test "serializes whatever" do
|
5
|
-
assert serializer.serialize?(RecordingsController.new)
|
6
|
-
end
|
7
|
-
|
3
|
+
class CacheKeeper::NewInstanceSerializerTest < ActiveSupport::TestCase
|
8
4
|
test "serializes the class name" do
|
9
5
|
serialized = serializer.serialize(RecordingsController.new)
|
10
6
|
|
@@ -21,6 +17,6 @@ class CacheKeeper::WhateverSerializerTest < ActiveSupport::TestCase
|
|
21
17
|
private
|
22
18
|
|
23
19
|
def serializer
|
24
|
-
CacheKeeper::
|
20
|
+
CacheKeeper::NewInstanceSerializer
|
25
21
|
end
|
26
22
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cache_keeper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Zamuner
|
@@ -37,12 +37,13 @@ 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
|
41
40
|
- app/jobs/cache_keeper/refresh_job.rb
|
42
41
|
- app/models/cache_keeper/cached_method.rb
|
43
42
|
- app/models/cache_keeper/cached_method/refreshable.rb
|
43
|
+
- app/models/cache_keeper/cached_method/serializable_target.rb
|
44
44
|
- app/serializers/cache_keeper/cached_method_serializer.rb
|
45
|
-
- app/serializers/cache_keeper/
|
45
|
+
- app/serializers/cache_keeper/marshal_serializer.rb
|
46
|
+
- app/serializers/cache_keeper/new_instance_serializer.rb
|
46
47
|
- bin/rails
|
47
48
|
- bin/release
|
48
49
|
- bin/test
|
@@ -50,8 +51,6 @@ files:
|
|
50
51
|
- lib/cache_keeper.rb
|
51
52
|
- lib/cache_keeper/caching.rb
|
52
53
|
- lib/cache_keeper/configuration.rb
|
53
|
-
- lib/cache_keeper/cron.rb
|
54
|
-
- lib/cache_keeper/cron/good_job_adapter.rb
|
55
54
|
- lib/cache_keeper/engine.rb
|
56
55
|
- lib/cache_keeper/manager.rb
|
57
56
|
- lib/cache_keeper/replace_method.rb
|
@@ -128,10 +127,14 @@ files:
|
|
128
127
|
- test/dummy/test/test_helper.rb
|
129
128
|
- test/dummy/vendor/.keep
|
130
129
|
- test/engine_test.rb
|
130
|
+
- test/jobs/refresh_job_test.rb
|
131
131
|
- test/manager_test.rb
|
132
|
+
- test/models/cached_method/refreshable_test.rb
|
133
|
+
- test/models/cached_method/serializable_target_test.rb
|
132
134
|
- test/models/cached_method_test.rb
|
133
135
|
- test/serializers/cached_method_serializer_test.rb
|
134
|
-
- test/serializers/
|
136
|
+
- test/serializers/marshal_serializer_test.rb
|
137
|
+
- test/serializers/new_instance_serializer_test.rb
|
135
138
|
- test/store_test.rb
|
136
139
|
- test/test_helper.rb
|
137
140
|
homepage: https://github.com/martinzamuner/cache_keeper
|
@@ -229,9 +232,13 @@ test_files:
|
|
229
232
|
- test/dummy/test/test_helper.rb
|
230
233
|
- test/dummy/vendor/.keep
|
231
234
|
- test/engine_test.rb
|
235
|
+
- test/jobs/refresh_job_test.rb
|
232
236
|
- test/manager_test.rb
|
237
|
+
- test/models/cached_method/refreshable_test.rb
|
238
|
+
- test/models/cached_method/serializable_target_test.rb
|
233
239
|
- test/models/cached_method_test.rb
|
234
240
|
- test/serializers/cached_method_serializer_test.rb
|
235
|
-
- test/serializers/
|
241
|
+
- test/serializers/marshal_serializer_test.rb
|
242
|
+
- test/serializers/new_instance_serializer_test.rb
|
236
243
|
- test/store_test.rb
|
237
244
|
- test/test_helper.rb
|
@@ -1,11 +0,0 @@
|
|
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
|
@@ -1,15 +0,0 @@
|
|
1
|
-
class CacheKeeper::WhateverSerializer < ActiveJob::Serializers::ObjectSerializer
|
2
|
-
def serialize?(argument)
|
3
|
-
true
|
4
|
-
end
|
5
|
-
|
6
|
-
def serialize(whatever)
|
7
|
-
super(
|
8
|
-
"klass" => whatever.class.to_s
|
9
|
-
)
|
10
|
-
end
|
11
|
-
|
12
|
-
def deserialize(hash)
|
13
|
-
hash["klass"].constantize.new
|
14
|
-
end
|
15
|
-
end
|