cache_json 1.2.1 → 1.2.6

Sign up to get free protection for your applications and to get access to all the features.
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: []