cache_json 1.2.1 → 1.2.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4c1572a9f2ee90814922450cf91ec662472b736ba86b78b1d526749c1aa79bc0
4
- data.tar.gz: b060d7548235ec62c9c1b350da2f874b138a74b988224de6e8f978fd22ee0a29
3
+ metadata.gz: 44125f970020a38afcbd640051d4f9b6d5565530b753d1e63079401d1ef607b2
4
+ data.tar.gz: 8a6d4e5469e88e118ff40cc346b80d422002a2e36cde0318538b452a530ffa1b
5
5
  SHA512:
6
- metadata.gz: fad61288414aa4631a48be02c418840eefad4c07d8f1aff890970fd243b01806b1d65618a74e70d80f89886ba79f4c78d7d96700119c8ae9c09359cc7a9ebf8a
7
- data.tar.gz: 9735828b606808072dc388176b4634fa6b7f49e28144b500dde1bc7cec17691cf226d362a58b3614d3a963d24c2f0154672ceee4238746552d87c081e0352b26
6
+ metadata.gz: b76526fafe43e2f8e51b785c18672fbf7f60c1ddd86ec98185499284bf40441c3dff96e3b55a771eb275ab33656548f6d012dd135c69b408057d5366cedd60af
7
+ data.tar.gz: 7ab99f8451f502bae4c9f4805507f0bbdedec4c57b29117c869f079647482342b1b54c9d1bd96495928175122918623fc22a18691b34e0961f28c0fbfe05f70f
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cache_json (1.2.0)
4
+ cache_json (1.2.6)
5
5
  redis (>= 3.3.5, < 5)
6
6
 
7
7
  GEM
@@ -15,7 +15,7 @@ GEM
15
15
  parallel (1.19.1)
16
16
  parser (2.7.0.3)
17
17
  ast (~> 2.4.0)
18
- rack (2.2.2)
18
+ rack (2.2.3)
19
19
  rack-protection (2.0.8.1)
20
20
  rack
21
21
  rainbow (3.0.0)
@@ -66,4 +66,4 @@ DEPENDENCIES
66
66
  timecop (~> 0.9.1)
67
67
 
68
68
  BUNDLED WITH
69
- 2.0.2
69
+ 2.2.3
data/README.md CHANGED
@@ -54,6 +54,44 @@ CacheJSON.configure do |config|
54
54
  end
55
55
  ```
56
56
 
57
+ ## Automatic refreshing (Sidekiq)
58
+
59
+ There is a simple Sidekiq job that lets you pre-compute selected classes with specified ranges of arguments. All you have to do is add a `refresh` option:
60
+
61
+ ```ruby
62
+ class ExpensiveJob
63
+
64
+ include CacheJSON::Base
65
+
66
+
67
+ cache_json_options(
68
+ time_to_expire: 1.hour,
69
+ refresh: {
70
+ buffer: 5.minutes,
71
+ arguments: {
72
+ first: (5..10),
73
+ second: ['one option', 'another option'],
74
+ third: 'the only option',
75
+ fourth: -> { ['proc result'] }
76
+ }
77
+ }
78
+ )
79
+ ...
80
+ end
81
+ ```
82
+
83
+ The Sidekiq job will take the Cartesian product of all the argument ranges/arrays (all the combinations).
84
+
85
+ We leave it to you to schedule the job. If you're using https://github.com/moove-it/sidekiq-scheduler, you can do something like this:
86
+
87
+ ```yml
88
+ cache_json_worker:
89
+ every: "20s"
90
+ class: CacheJSON::Worker
91
+ ```
92
+
93
+ Whenever the worker runs, it checks which results have expired, and refreshes only those. If you pass in the `buffer` option, it will actually refresh keys that are that far away from expiring. In the example above, the worker will refresh the cache 5 minutes before it expires. This is good if you want to avoid cache misses altogether.
94
+
57
95
  ## Development
58
96
 
59
97
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -31,6 +31,10 @@ module CacheJSON
31
31
  $redis.del(class_key)
32
32
  end
33
33
 
34
+ def cache_expiring_soon?
35
+ $redis.ttl(full_key) < options[:refresh][:buffer].to_i
36
+ end
37
+
34
38
  private
35
39
 
36
40
  def full_key
@@ -8,7 +8,7 @@ module CacheJSON
8
8
  base.extend(ClassMethods)
9
9
  end
10
10
 
11
- def results(args)
11
+ def results(args = {})
12
12
  raise ArgumentError, 'Must use keyword arguments' unless args.is_a?(Hash)
13
13
 
14
14
  options = self.class.cache_json_full_options
@@ -17,6 +17,11 @@ module CacheJSON
17
17
  JSON.parse(refresh_cache!(args: args, cache: cache).to_json) # stringify keys
18
18
  end
19
19
 
20
+ def cache_expiring_soon?(args:, cache: nil)
21
+ cache ||= Cache.new(args: args, options: self.class.cache_json_full_options)
22
+ cache.cache_expiring_soon?
23
+ end
24
+
20
25
  def clear_cache!
21
26
  Cache.new(options: self.class.cache_json_full_options).clear_cache!
22
27
  end
@@ -54,6 +59,10 @@ module CacheJSON
54
59
  adapter.clear_cache!
55
60
  end
56
61
 
62
+ def cache_expiring_soon?
63
+ adapter.cache_expiring_soon?
64
+ end
65
+
57
66
  def adapter
58
67
  @adapter ||= CacheJSON::Adapters::Redis.new(args: args, options: options)
59
68
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CacheJSON
4
- VERSION = '1.2.1'
4
+ VERSION = '1.2.6'
5
5
  end
@@ -5,7 +5,6 @@ begin
5
5
  rescue LoadError
6
6
  nil
7
7
  end
8
-
9
8
  module CacheJSON
10
9
  class Worker
11
10
  if defined?(Sidekiq)
@@ -18,66 +17,80 @@ module CacheJSON
18
17
  end
19
18
  end
20
19
 
21
- def perform(klass: nil, args: {})
20
+ def perform(params="{}")
21
+ parsed_params = JSON.parse(params)
22
+ klass = parsed_params["klass"]
23
+ args = (parsed_params["args"] || {}).transform_keys(&:to_sym)
22
24
  if klass
23
- klass.new.refresh_cache!(args: args)
25
+ klass = Object.const_get(klass)
26
+ klass.new.refresh_cache!(args: args) if should_refresh?(klass, args)
24
27
  else
25
- generate_workers
28
+ AllPermutations.new.results.each do |perm|
29
+ if should_refresh?(perm[:klass], perm[:args])
30
+ perm[:klass] = perm[:klass].to_s
31
+ CacheJSON::Worker.perform_async(perm.to_json)
32
+ end
33
+ end
26
34
  end
27
35
  end
28
36
 
29
37
  private
30
38
 
31
- def generate_workers
32
- all_cache_classes.each do |klass|
33
- all_argument_permutations(klass).each do |args|
34
- CacheJSON::Worker.new.perform(klass: klass, args: args) if should_refresh?(klass, args)
35
- end
36
- end
39
+ def should_refresh?(klass, args)
40
+ !klass.new.check_cache(args: args) || klass.new.cache_expiring_soon?(args: args)
37
41
  end
38
42
 
39
- def all_cache_classes
40
- # TODO: make this more efficient
41
- ObjectSpace.each_object(Class).select do |klass|
42
- klass.included_modules.include? CacheJSON::Base
43
+ class AllPermutations
44
+ def results
45
+ all_cache_classes.flat_map do |klass|
46
+ all_argument_permutations(klass).map do |args|
47
+ {
48
+ klass: klass,
49
+ args: args
50
+ }
51
+ end
52
+ end
43
53
  end
44
- end
45
54
 
46
- def all_argument_permutations(klass)
47
- refresh_options = klass.cache_json_full_options[:refresh]
48
- if refresh_options
49
- all_combinations_with_fixed_points({}, refresh_options[:arguments])
50
- else
51
- []
55
+ def all_cache_classes
56
+ # TODO: make this more efficient
57
+ ObjectSpace.each_object(Class).select do |klass|
58
+ klass.included_modules.include? CacheJSON::Base
59
+ end
52
60
  end
53
- end
54
61
 
55
- def all_combinations_with_fixed_points(fixed_points, full_hash)
56
- non_fixed_points = full_hash.dup.delete_if { |k, _| fixed_points.key?(k) }
57
- if non_fixed_points.empty?
58
- [fixed_points]
59
- else
60
- pivot_key = non_fixed_points.keys.first
61
- values_for_key(non_fixed_points, pivot_key).flat_map do |pivot_key_value|
62
- new_fixed_points = fixed_points.merge(Hash[pivot_key, pivot_key_value])
63
- all_combinations_with_fixed_points(new_fixed_points, full_hash)
62
+ def all_argument_permutations(klass)
63
+ refresh_options = klass.cache_json_full_options[:refresh]
64
+ if refresh_options
65
+ all_combinations_with_fixed_points({}, refresh_options[:arguments])
66
+ else
67
+ []
64
68
  end
65
69
  end
66
- end
67
70
 
68
- def values_for_key(hsh, key)
69
- pivot_key_values = hsh[key]
70
- if pivot_key_values.is_a?(Proc)
71
- pivot_key_values.call
72
- elsif pivot_key_values.is_a?(Range) || pivot_key_values.is_a?(Array)
73
- pivot_key_values
74
- else
75
- [pivot_key_values]
71
+ def all_combinations_with_fixed_points(fixed_points, full_hash)
72
+ non_fixed_points = full_hash.dup.delete_if { |k, _| fixed_points.key?(k) }
73
+ if non_fixed_points.empty?
74
+ [fixed_points]
75
+ else
76
+ pivot_key = non_fixed_points.keys.first
77
+ values_for_key(non_fixed_points, pivot_key).flat_map do |pivot_key_value|
78
+ new_fixed_points = fixed_points.merge(Hash[pivot_key, pivot_key_value])
79
+ all_combinations_with_fixed_points(new_fixed_points, full_hash)
80
+ end
81
+ end
76
82
  end
77
- end
78
83
 
79
- def should_refresh?(klass, args)
80
- !klass.new.check_cache(args: args)
84
+ def values_for_key(hsh, key)
85
+ pivot_key_values = hsh[key]
86
+ if pivot_key_values.is_a?(Proc)
87
+ pivot_key_values.call
88
+ elsif pivot_key_values.is_a?(Range) || pivot_key_values.is_a?(Array)
89
+ pivot_key_values
90
+ else
91
+ [pivot_key_values]
92
+ end
93
+ end
81
94
  end
82
95
  end
83
96
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cache_json
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Gut
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-14 00:00:00.000000000 Z
11
+ date: 2021-04-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -166,7 +166,7 @@ licenses:
166
166
  metadata:
167
167
  homepage_uri: https://github.com/loopsupport/cache_json
168
168
  source_code_uri: https://github.com/loopsupport/cache_json
169
- post_install_message:
169
+ post_install_message:
170
170
  rdoc_options: []
171
171
  require_paths:
172
172
  - lib
@@ -181,8 +181,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
181
181
  - !ruby/object:Gem::Version
182
182
  version: '0'
183
183
  requirements: []
184
- rubygems_version: 3.1.2
185
- signing_key:
184
+ rubygems_version: 3.2.3
185
+ signing_key:
186
186
  specification_version: 4
187
187
  summary: Extremely simple Redis caching for any Ruby class
188
188
  test_files: []