cache_keeper 0.2.1 → 0.4.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/ci.yml +10 -3
- data/.gitignore +2 -0
- data/.rubocop.yml +122 -0
- data/Gemfile +17 -3
- data/README.md +30 -15
- 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 +5 -7
- data/app/models/cache_keeper/cached_method/serializable_target.rb +18 -0
- data/app/models/cache_keeper/cached_method.rb +14 -11
- data/app/serializers/cache_keeper/marshal_serializer.rb +9 -0
- data/app/serializers/cache_keeper/new_instance_serializer.rb +9 -0
- data/bin/rails +6 -6
- data/lib/cache_keeper/configuration.rb +1 -17
- data/lib/cache_keeper/engine.rb +4 -16
- 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 +15 -0
- data/test/models/cached_method/refreshable_test.rb +14 -0
- data/test/models/cached_method/serializable_target_test.rb +24 -0
- data/test/models/cached_method_test.rb +2 -2
- data/test/serializers/marshal_serializer_test.rb +24 -0
- data/test/serializers/{whatever_serializer_test.rb → new_instance_serializer_test.rb} +2 -6
- metadata +16 -9
- data/Gemfile.lock +0 -199
- 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: 04c55e34ac5e0676e81456a04f7edae71cf0c79c6cd5be9e135c56561f6439be
|
4
|
+
data.tar.gz: 6f9d9bc0bd404cd350f1cf7ff48b8c59bbff60dbeeda754c052ca22457720b8a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1eec12fc16cf629cbe1b3502918b67d6d420bb812c1ed88088a809b07faf31ec981dfddb0d094507f0cd9522238134b1bc60ff011f0d99a12339144a5ba0a3d2
|
7
|
+
data.tar.gz: 6a93852da524a5e478166bc24d0bee53973a3343a8b55c2574ed67259f3e5ffc7f927b31bd35e257fe0107073e69fc32a99e608614b07ab736fa103e8ce33adc
|
data/.github/workflows/ci.yml
CHANGED
@@ -4,13 +4,20 @@ jobs:
|
|
4
4
|
tests:
|
5
5
|
strategy:
|
6
6
|
matrix:
|
7
|
-
ruby-version:
|
8
|
-
- "2.7"
|
9
|
-
- "3.0"
|
10
7
|
rails-version:
|
11
8
|
- "6.1"
|
12
9
|
- "7.0"
|
10
|
+
- "7.1"
|
13
11
|
- "main"
|
12
|
+
include:
|
13
|
+
- rails-version: "6.1"
|
14
|
+
ruby-version: "2.5"
|
15
|
+
- rails-version: "7.0"
|
16
|
+
ruby-version: "2.7"
|
17
|
+
- rails-version: "7.1"
|
18
|
+
ruby-version: "2.7"
|
19
|
+
- rails-version: "main"
|
20
|
+
ruby-version: "3.2"
|
14
21
|
|
15
22
|
env:
|
16
23
|
RAILS_VERSION: "${{ matrix.rails-version }}"
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-rails
|
3
|
+
- rubocop-performance
|
4
|
+
|
5
|
+
AllCops:
|
6
|
+
Exclude:
|
7
|
+
- '**/db/**/*'
|
8
|
+
- '**/config/**/*'
|
9
|
+
- '**/tmp/**/*'
|
10
|
+
- '**/templates/**/*'
|
11
|
+
- '**/vendor/**/*'
|
12
|
+
- '**/node_modules/**/*'
|
13
|
+
TargetRubyVersion: 3.2.2
|
14
|
+
|
15
|
+
# Relaxed Ruby Style
|
16
|
+
Style/Alias:
|
17
|
+
Enabled: false
|
18
|
+
StyleGuide: https://relaxed.ruby.style/#stylealias
|
19
|
+
|
20
|
+
Style/AsciiComments:
|
21
|
+
Enabled: false
|
22
|
+
StyleGuide: https://relaxed.ruby.style/#styleasciicomments
|
23
|
+
|
24
|
+
Style/BeginBlock:
|
25
|
+
Enabled: false
|
26
|
+
StyleGuide: https://relaxed.ruby.style/#stylebeginblock
|
27
|
+
|
28
|
+
Style/BlockDelimiters:
|
29
|
+
Enabled: false
|
30
|
+
StyleGuide: https://relaxed.ruby.style/#styleblockdelimiters
|
31
|
+
|
32
|
+
Style/Documentation:
|
33
|
+
Enabled: false
|
34
|
+
StyleGuide: https://relaxed.ruby.style/#styledocumentation
|
35
|
+
|
36
|
+
Style/EndBlock:
|
37
|
+
Enabled: false
|
38
|
+
StyleGuide: https://relaxed.ruby.style/#styleendblock
|
39
|
+
|
40
|
+
Style/GuardClause:
|
41
|
+
Enabled: false
|
42
|
+
|
43
|
+
Style/IfUnlessModifier:
|
44
|
+
Enabled: false
|
45
|
+
StyleGuide: https://relaxed.ruby.style/#styleifunlessmodifier
|
46
|
+
|
47
|
+
Style/ModuleFunction:
|
48
|
+
Enabled: false
|
49
|
+
StyleGuide: https://relaxed.ruby.style/#stylemodulefunction
|
50
|
+
|
51
|
+
Style/MultilineBlockChain:
|
52
|
+
Enabled: false
|
53
|
+
StyleGuide: https://relaxed.ruby.style/#stylemultilineblockchain
|
54
|
+
|
55
|
+
Style/NegatedIf:
|
56
|
+
Enabled: false
|
57
|
+
StyleGuide: https://relaxed.ruby.style/#stylenegatedif
|
58
|
+
|
59
|
+
Style/NegatedWhile:
|
60
|
+
Enabled: false
|
61
|
+
StyleGuide: https://relaxed.ruby.style/#stylenegatedwhile
|
62
|
+
|
63
|
+
Style/NumericPredicate:
|
64
|
+
Enabled: false
|
65
|
+
StyleGuide: https://relaxed.ruby.style/#stylenumericpredicate
|
66
|
+
|
67
|
+
Style/PercentLiteralDelimiters:
|
68
|
+
Enabled: false
|
69
|
+
StyleGuide: https://relaxed.ruby.style/#stylepercentliteraldelimiters
|
70
|
+
|
71
|
+
Style/WhileUntilModifier:
|
72
|
+
Enabled: false
|
73
|
+
StyleGuide: https://relaxed.ruby.style/#stylewhileuntilmodifier
|
74
|
+
|
75
|
+
Style/WordArray:
|
76
|
+
Enabled: false
|
77
|
+
StyleGuide: https://relaxed.ruby.style/#stylewordarray
|
78
|
+
|
79
|
+
Lint/AmbiguousRegexpLiteral:
|
80
|
+
Enabled: false
|
81
|
+
StyleGuide: https://relaxed.ruby.style/#lintambiguousregexpliteral
|
82
|
+
|
83
|
+
Lint/AssignmentInCondition:
|
84
|
+
Enabled: false
|
85
|
+
StyleGuide: https://relaxed.ruby.style/#lintassignmentincondition
|
86
|
+
|
87
|
+
Layout/LineLength:
|
88
|
+
Enabled: false
|
89
|
+
|
90
|
+
Metrics:
|
91
|
+
Enabled: false
|
92
|
+
|
93
|
+
# Custom
|
94
|
+
Performance:
|
95
|
+
Exclude:
|
96
|
+
- '**/spec/**/*'
|
97
|
+
|
98
|
+
Style/FrozenStringLiteralComment:
|
99
|
+
Enabled: false
|
100
|
+
|
101
|
+
Style/AndOr:
|
102
|
+
Enabled: true
|
103
|
+
EnforcedStyle: conditionals
|
104
|
+
|
105
|
+
Style/ClassAndModuleChildren:
|
106
|
+
Enabled: false
|
107
|
+
|
108
|
+
Style/HashSyntax:
|
109
|
+
Enabled: false
|
110
|
+
|
111
|
+
Style/MixinGrouping:
|
112
|
+
Enabled: false
|
113
|
+
|
114
|
+
Style/RegexpLiteral:
|
115
|
+
Enabled: false
|
116
|
+
|
117
|
+
Style/StringConcatenation:
|
118
|
+
Enabled: false
|
119
|
+
|
120
|
+
Style/StringLiterals:
|
121
|
+
Enabled: true
|
122
|
+
EnforcedStyle: double_quotes
|
data/Gemfile
CHANGED
@@ -2,8 +2,22 @@ source "https://rubygems.org"
|
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
-
|
6
|
-
gem "byebug"
|
5
|
+
rails_version = ENV.fetch("RAILS_VERSION", "7.1")
|
7
6
|
|
8
|
-
|
7
|
+
rails_constraint =
|
8
|
+
if rails_version == "main"
|
9
|
+
{ github: "rails/rails" }
|
10
|
+
else
|
11
|
+
"~> #{rails_version}.0"
|
12
|
+
end
|
13
|
+
|
14
|
+
gem "rails", rails_constraint
|
9
15
|
gem "sqlite3"
|
16
|
+
|
17
|
+
group :debug do
|
18
|
+
gem "byebug"
|
19
|
+
|
20
|
+
gem "rubocop"
|
21
|
+
gem "rubocop-performance"
|
22
|
+
gem "rubocop-rails"
|
23
|
+
end
|
data/README.md
CHANGED
@@ -29,25 +29,49 @@ bundle add cache_keeper
|
|
29
29
|
CacheKeeper provides a `caches` method that will cache the result of the methods you give it:
|
30
30
|
|
31
31
|
```ruby
|
32
|
-
|
33
|
-
caches :
|
32
|
+
class Recording < ApplicationRecord
|
33
|
+
caches :slow_method, :really_slow_method, expires_in: 1.hour, must_revalidate: true
|
34
|
+
caches :incredibly_slow_method, expires_in: 2.hours, key: -> { "custom-key/#{id}" }
|
35
|
+
|
36
|
+
def slow_method
|
37
|
+
...
|
38
|
+
end
|
39
|
+
|
40
|
+
def really_slow_method
|
41
|
+
...
|
42
|
+
end
|
43
|
+
|
44
|
+
def incredibly_slow_method
|
45
|
+
...
|
46
|
+
end
|
47
|
+
end
|
34
48
|
```
|
35
49
|
|
36
50
|
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
51
|
|
38
52
|
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
53
|
|
54
|
+
CacheKeeper will compose cache keys from the name of the method and the instance's `cache_key` if it's defined or the name of the class otherwise. You can pass a `key` option to customize the cache key if you need it. It accepts [the same values](https://guides.rubyonrails.org/caching_with_rails.html#cache-keys) as `Rails.cache.fetch`, as well as procs or lambdas in case you need access to the instance.
|
55
|
+
|
40
56
|
It's important to note that it will only work with methods that don't take any arguments.
|
41
57
|
|
42
|
-
###
|
58
|
+
### Serialization
|
43
59
|
|
44
|
-
|
60
|
+
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
61
|
|
46
62
|
```ruby
|
47
|
-
|
63
|
+
class Example
|
64
|
+
# Generate a new instance using an empty initializer (Example.new)
|
65
|
+
# Useful for controllers and for POROs with no arguments
|
66
|
+
caches :slow_method, serializer: :new_instance
|
67
|
+
|
68
|
+
# Replicate the old instance using Marshal.dump and Marshal.load
|
69
|
+
# Useful in most other cases, but make sure the dump is not too big
|
70
|
+
caches :slow_method, serializer: :marshal
|
71
|
+
end
|
48
72
|
```
|
49
73
|
|
50
|
-
|
74
|
+
If those options don't work for you, you can always [write custom serializers](https://guides.rubyonrails.org/active_job_basics.html#serializers) for your classes.
|
51
75
|
|
52
76
|
|
53
77
|
## Configuration
|
@@ -63,15 +87,6 @@ Rails.application.configure do
|
|
63
87
|
# The queue to use for the refresh jobs.
|
64
88
|
# Default: nil (uses the default queue)
|
65
89
|
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
90
|
end
|
76
91
|
```
|
77
92
|
|
@@ -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(
|
3
|
-
Rails.cache.fetch(cache_key, expires_in: expires_in) do
|
4
|
-
|
2
|
+
def refresh(target)
|
3
|
+
Rails.cache.fetch(cache_key(target), expires_in: expires_in) do
|
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
|
|
@@ -13,18 +14,16 @@ class CacheKeeper::CachedMethod
|
|
13
14
|
:"__#{method_name}__hooked__"
|
14
15
|
end
|
15
16
|
|
16
|
-
def
|
17
|
-
cache_entry
|
18
|
-
end
|
17
|
+
def call(target)
|
18
|
+
cache_entry = cache_entry(target)
|
19
19
|
|
20
|
-
def call(instance)
|
21
20
|
if cache_entry.blank?
|
22
|
-
refresh
|
21
|
+
refresh target
|
23
22
|
elsif cache_entry.expired?
|
24
23
|
if must_revalidate?
|
25
|
-
refresh
|
24
|
+
refresh target
|
26
25
|
else
|
27
|
-
refresh_later
|
26
|
+
refresh_later target
|
28
27
|
|
29
28
|
cache_entry.value
|
30
29
|
end
|
@@ -35,12 +34,16 @@ class CacheKeeper::CachedMethod
|
|
35
34
|
|
36
35
|
private
|
37
36
|
|
38
|
-
def cache_entry
|
39
|
-
Rails.cache.send :read_entry, Rails.cache.send(:normalize_key, cache_key, {})
|
37
|
+
def cache_entry(target)
|
38
|
+
Rails.cache.send :read_entry, Rails.cache.send(:normalize_key, cache_key(target), {})
|
40
39
|
end
|
41
40
|
|
42
|
-
def cache_key
|
43
|
-
[
|
41
|
+
def cache_key(target)
|
42
|
+
if options[:key].present?
|
43
|
+
options[:key].is_a?(Proc) ? target.instance_exec(&options[:key]) : options[:key]
|
44
|
+
else
|
45
|
+
target.respond_to?(:cache_key) ? ["CacheKeeper", target, method_name] : ["CacheKeeper", klass, method_name]
|
46
|
+
end
|
44
47
|
end
|
45
48
|
|
46
49
|
def expires_in
|
@@ -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
|
data/bin/rails
CHANGED
@@ -2,12 +2,12 @@
|
|
2
2
|
# This command will automatically be run when you run "rails" with Rails gems
|
3
3
|
# installed from the root of your application.
|
4
4
|
|
5
|
-
ENGINE_ROOT = File.expand_path(
|
6
|
-
APP_PATH = File.expand_path(
|
5
|
+
ENGINE_ROOT = File.expand_path("..", __dir__)
|
6
|
+
APP_PATH = File.expand_path("../test/dummy/config/application", __dir__)
|
7
7
|
|
8
8
|
# Set up gems listed in the Gemfile.
|
9
|
-
ENV[
|
10
|
-
require
|
9
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
10
|
+
require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
|
11
11
|
|
12
|
-
require
|
13
|
-
require
|
12
|
+
require "rails/all"
|
13
|
+
require "rails/engine/commands"
|
@@ -1,8 +1,7 @@
|
|
1
1
|
module CacheKeeper
|
2
2
|
class Configuration
|
3
3
|
DEFAULT_MUST_REVALIDATE = false
|
4
|
-
DEFAULT_QUEUES = {}
|
5
|
-
DEFAULT_CRON_EXPRESSION = "*/15 * * * *" # Every 15 minutes, every day
|
4
|
+
DEFAULT_QUEUES = {}.freeze
|
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,30 +2,18 @@ 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
|
-
initializer "cache_keeper.active_job_serializer" do
|
10
|
+
initializer "cache_keeper.active_job_serializer" do
|
17
11
|
config.to_prepare do
|
18
12
|
Rails.application.config.active_job.custom_serializers << CacheKeeper::CachedMethodSerializer
|
19
13
|
end
|
20
14
|
end
|
21
15
|
|
22
|
-
initializer "cache_keeper.
|
23
|
-
config.to_prepare do
|
24
|
-
CacheKeeper.configuration.cron_adapter&.setup
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
initializer "cache_keeper.caching_methods" do |app|
|
16
|
+
initializer "cache_keeper.caching_methods" do
|
29
17
|
ActiveSupport.on_load :action_controller do
|
30
18
|
ActionController::Base.send :include, CacheKeeper::Caching
|
31
19
|
end
|
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,15 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class CacheKeeper::RefreshJobTest < ActiveSupport::TestCase
|
4
|
+
include ActiveJob::TestHelper
|
5
|
+
|
6
|
+
test "uses the correct queue" do
|
7
|
+
CacheKeeper.configuration.queues[:refresh] = "refresh"
|
8
|
+
recording = Recording.create(number: 5)
|
9
|
+
cached_method = CacheKeeper.manager.cached_methods.first
|
10
|
+
|
11
|
+
assert_performed_with(queue: "refresh") do
|
12
|
+
CacheKeeper::RefreshJob.perform_later cached_method, recording
|
13
|
+
end
|
14
|
+
end
|
15
|
+
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) 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
|
@@ -2,14 +2,14 @@ require "test_helper"
|
|
2
2
|
|
3
3
|
class CacheKeeper::CachedMethodTest < ActiveSupport::TestCase
|
4
4
|
test "#call caches the result of the original method" do
|
5
|
-
recording = Recording.
|
5
|
+
recording = Recording.create(number: 5)
|
6
6
|
cached_method = manager.handle(Recording, :another_method, expires_in: 1.hour)
|
7
7
|
manager.activate_if_handling(Recording, :another_method)
|
8
8
|
|
9
9
|
result = cached_method.call(recording)
|
10
10
|
|
11
11
|
assert_equal 5, result
|
12
|
-
assert cache_has_key? "CacheKeeper/
|
12
|
+
assert cache_has_key? "CacheKeeper/recordings/#{recording.id}/another_method"
|
13
13
|
end
|
14
14
|
|
15
15
|
private
|
@@ -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,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cache_keeper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
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-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -32,17 +32,18 @@ extra_rdoc_files: []
|
|
32
32
|
files:
|
33
33
|
- ".github/workflows/ci.yml"
|
34
34
|
- ".gitignore"
|
35
|
+
- ".rubocop.yml"
|
35
36
|
- Gemfile
|
36
|
-
- Gemfile.lock
|
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
|
data/Gemfile.lock
DELETED
@@ -1,199 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
cache_keeper (0.2.1)
|
5
|
-
rails (>= 6.1.0)
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: https://rubygems.org/
|
9
|
-
specs:
|
10
|
-
actioncable (7.1.1)
|
11
|
-
actionpack (= 7.1.1)
|
12
|
-
activesupport (= 7.1.1)
|
13
|
-
nio4r (~> 2.0)
|
14
|
-
websocket-driver (>= 0.6.1)
|
15
|
-
zeitwerk (~> 2.6)
|
16
|
-
actionmailbox (7.1.1)
|
17
|
-
actionpack (= 7.1.1)
|
18
|
-
activejob (= 7.1.1)
|
19
|
-
activerecord (= 7.1.1)
|
20
|
-
activestorage (= 7.1.1)
|
21
|
-
activesupport (= 7.1.1)
|
22
|
-
mail (>= 2.7.1)
|
23
|
-
net-imap
|
24
|
-
net-pop
|
25
|
-
net-smtp
|
26
|
-
actionmailer (7.1.1)
|
27
|
-
actionpack (= 7.1.1)
|
28
|
-
actionview (= 7.1.1)
|
29
|
-
activejob (= 7.1.1)
|
30
|
-
activesupport (= 7.1.1)
|
31
|
-
mail (~> 2.5, >= 2.5.4)
|
32
|
-
net-imap
|
33
|
-
net-pop
|
34
|
-
net-smtp
|
35
|
-
rails-dom-testing (~> 2.2)
|
36
|
-
actionpack (7.1.1)
|
37
|
-
actionview (= 7.1.1)
|
38
|
-
activesupport (= 7.1.1)
|
39
|
-
nokogiri (>= 1.8.5)
|
40
|
-
rack (>= 2.2.4)
|
41
|
-
rack-session (>= 1.0.1)
|
42
|
-
rack-test (>= 0.6.3)
|
43
|
-
rails-dom-testing (~> 2.2)
|
44
|
-
rails-html-sanitizer (~> 1.6)
|
45
|
-
actiontext (7.1.1)
|
46
|
-
actionpack (= 7.1.1)
|
47
|
-
activerecord (= 7.1.1)
|
48
|
-
activestorage (= 7.1.1)
|
49
|
-
activesupport (= 7.1.1)
|
50
|
-
globalid (>= 0.6.0)
|
51
|
-
nokogiri (>= 1.8.5)
|
52
|
-
actionview (7.1.1)
|
53
|
-
activesupport (= 7.1.1)
|
54
|
-
builder (~> 3.1)
|
55
|
-
erubi (~> 1.11)
|
56
|
-
rails-dom-testing (~> 2.2)
|
57
|
-
rails-html-sanitizer (~> 1.6)
|
58
|
-
activejob (7.1.1)
|
59
|
-
activesupport (= 7.1.1)
|
60
|
-
globalid (>= 0.3.6)
|
61
|
-
activemodel (7.1.1)
|
62
|
-
activesupport (= 7.1.1)
|
63
|
-
activerecord (7.1.1)
|
64
|
-
activemodel (= 7.1.1)
|
65
|
-
activesupport (= 7.1.1)
|
66
|
-
timeout (>= 0.4.0)
|
67
|
-
activestorage (7.1.1)
|
68
|
-
actionpack (= 7.1.1)
|
69
|
-
activejob (= 7.1.1)
|
70
|
-
activerecord (= 7.1.1)
|
71
|
-
activesupport (= 7.1.1)
|
72
|
-
marcel (~> 1.0)
|
73
|
-
activesupport (7.1.1)
|
74
|
-
base64
|
75
|
-
bigdecimal
|
76
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
77
|
-
connection_pool (>= 2.2.5)
|
78
|
-
drb
|
79
|
-
i18n (>= 1.6, < 2)
|
80
|
-
minitest (>= 5.1)
|
81
|
-
mutex_m
|
82
|
-
tzinfo (~> 2.0)
|
83
|
-
base64 (0.1.1)
|
84
|
-
bigdecimal (3.1.4)
|
85
|
-
builder (3.2.4)
|
86
|
-
byebug (11.1.3)
|
87
|
-
concurrent-ruby (1.2.2)
|
88
|
-
connection_pool (2.4.1)
|
89
|
-
crass (1.0.6)
|
90
|
-
date (3.3.3)
|
91
|
-
drb (2.1.1)
|
92
|
-
ruby2_keywords
|
93
|
-
erubi (1.12.0)
|
94
|
-
globalid (1.2.1)
|
95
|
-
activesupport (>= 6.1)
|
96
|
-
i18n (1.14.1)
|
97
|
-
concurrent-ruby (~> 1.0)
|
98
|
-
io-console (0.6.0)
|
99
|
-
irb (1.8.3)
|
100
|
-
rdoc
|
101
|
-
reline (>= 0.3.8)
|
102
|
-
loofah (2.21.4)
|
103
|
-
crass (~> 1.0.2)
|
104
|
-
nokogiri (>= 1.12.0)
|
105
|
-
mail (2.8.1)
|
106
|
-
mini_mime (>= 0.1.1)
|
107
|
-
net-imap
|
108
|
-
net-pop
|
109
|
-
net-smtp
|
110
|
-
marcel (1.0.2)
|
111
|
-
mini_mime (1.1.5)
|
112
|
-
minitest (5.20.0)
|
113
|
-
mutex_m (0.1.2)
|
114
|
-
net-imap (0.4.2)
|
115
|
-
date
|
116
|
-
net-protocol
|
117
|
-
net-pop (0.1.2)
|
118
|
-
net-protocol
|
119
|
-
net-protocol (0.2.1)
|
120
|
-
timeout
|
121
|
-
net-smtp (0.4.0)
|
122
|
-
net-protocol
|
123
|
-
nio4r (2.5.9)
|
124
|
-
nokogiri (1.15.4-arm64-darwin)
|
125
|
-
racc (~> 1.4)
|
126
|
-
nokogiri (1.15.4-x86_64-linux)
|
127
|
-
racc (~> 1.4)
|
128
|
-
psych (5.1.1.1)
|
129
|
-
stringio
|
130
|
-
racc (1.7.1)
|
131
|
-
rack (3.0.8)
|
132
|
-
rack-session (2.0.0)
|
133
|
-
rack (>= 3.0.0)
|
134
|
-
rack-test (2.1.0)
|
135
|
-
rack (>= 1.3)
|
136
|
-
rackup (2.1.0)
|
137
|
-
rack (>= 3)
|
138
|
-
webrick (~> 1.8)
|
139
|
-
rails (7.1.1)
|
140
|
-
actioncable (= 7.1.1)
|
141
|
-
actionmailbox (= 7.1.1)
|
142
|
-
actionmailer (= 7.1.1)
|
143
|
-
actionpack (= 7.1.1)
|
144
|
-
actiontext (= 7.1.1)
|
145
|
-
actionview (= 7.1.1)
|
146
|
-
activejob (= 7.1.1)
|
147
|
-
activemodel (= 7.1.1)
|
148
|
-
activerecord (= 7.1.1)
|
149
|
-
activestorage (= 7.1.1)
|
150
|
-
activesupport (= 7.1.1)
|
151
|
-
bundler (>= 1.15.0)
|
152
|
-
railties (= 7.1.1)
|
153
|
-
rails-dom-testing (2.2.0)
|
154
|
-
activesupport (>= 5.0.0)
|
155
|
-
minitest
|
156
|
-
nokogiri (>= 1.6)
|
157
|
-
rails-html-sanitizer (1.6.0)
|
158
|
-
loofah (~> 2.21)
|
159
|
-
nokogiri (~> 1.14)
|
160
|
-
railties (7.1.1)
|
161
|
-
actionpack (= 7.1.1)
|
162
|
-
activesupport (= 7.1.1)
|
163
|
-
irb
|
164
|
-
rackup (>= 1.0.0)
|
165
|
-
rake (>= 12.2)
|
166
|
-
thor (~> 1.0, >= 1.2.2)
|
167
|
-
zeitwerk (~> 2.6)
|
168
|
-
rake (13.0.6)
|
169
|
-
rdoc (6.5.0)
|
170
|
-
psych (>= 4.0.0)
|
171
|
-
reline (0.3.9)
|
172
|
-
io-console (~> 0.5)
|
173
|
-
ruby2_keywords (0.0.5)
|
174
|
-
sqlite3 (1.6.7-arm64-darwin)
|
175
|
-
sqlite3 (1.6.7-x86_64-linux)
|
176
|
-
stringio (3.0.8)
|
177
|
-
thor (1.3.0)
|
178
|
-
timeout (0.4.0)
|
179
|
-
tzinfo (2.0.6)
|
180
|
-
concurrent-ruby (~> 1.0)
|
181
|
-
webrick (1.8.1)
|
182
|
-
websocket-driver (0.7.6)
|
183
|
-
websocket-extensions (>= 0.1.0)
|
184
|
-
websocket-extensions (0.1.5)
|
185
|
-
zeitwerk (2.6.12)
|
186
|
-
|
187
|
-
PLATFORMS
|
188
|
-
arm64-darwin-22
|
189
|
-
x86_64-linux
|
190
|
-
|
191
|
-
DEPENDENCIES
|
192
|
-
byebug
|
193
|
-
cache_keeper!
|
194
|
-
rails (>= 6.1)
|
195
|
-
rake
|
196
|
-
sqlite3
|
197
|
-
|
198
|
-
BUNDLED WITH
|
199
|
-
2.4.19
|
@@ -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
|