cache_json 1.2.0 → 1.2.5

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: fe1d01d761ef7ff3aff1777d3a019704095b1f50a9ba2ab57fd5a5ba72e02816
4
- data.tar.gz: 64b4ac0d7350fbb3125c11c16c9d952e847efa8d230cd54d024f56cfb7ede509
3
+ metadata.gz: 5df5d41a7515bef89f1d04f0368a8e4704a2ecf7ee46e8c43fa4a39b76850a37
4
+ data.tar.gz: 11baaf8f7055c0dfb5ae0928e47f85d881e0dc83ffb368c8744d2573c42ba5d4
5
5
  SHA512:
6
- metadata.gz: ad7911c949d27461f994f16bfcb19e93a5c0830e7b606ccf87e4362042d888056d9a9e029608381550a997297691b34e5570827eb2da64666b0b8d407647fb8e
7
- data.tar.gz: 1cfde86c126160747298a70ef8ebc07dcfb0be8e6e66945c464262a99de4a227ef4e264a0d4e265ba5724afd1a5cee5e94dca78eea53e757b3cb0fdfa4c94bf7
6
+ metadata.gz: 70db145dc314055f2f5200a1e51cd05ba807ac2489765f22275f3ee747a15dac358907c2597b888a918c771d6396c200a52c9d7113424b3504fe2ce07addc8e5
7
+ data.tar.gz: a99dc593f2e01d575516489dd8321d7d2969b6b05b723f740fc02bd1752d62cedda91d37a5cee4763b6bafa6e29799d8d33570ff01af7f0b56f81f52ac89c7a5
data/.rubocop.yml CHANGED
@@ -1,14 +1,41 @@
1
- Style/GlobalVars:
2
- Enabled: false
3
-
4
- Style/Documentation:
5
- Enabled: false
1
+ Metrics/BlockLength:
2
+ Enabled: true
3
+ Exclude:
4
+ - "spec/**/*"
6
5
 
7
- Metrics/LineLength:
6
+ Layout/LineLength:
8
7
  Enabled: true
9
8
  Max: 100
10
9
 
11
- Metrics/BlockLength:
10
+ Layout/EmptyLinesAroundAttributeAccessor:
12
11
  Enabled: true
13
- Exclude:
14
- - "spec/**/*"
12
+
13
+ Layout/SpaceAroundMethodCallOperator:
14
+ Enabled: true
15
+
16
+ Lint/RaiseException:
17
+ Enabled: true
18
+
19
+ Lint/StructNewOverride:
20
+ Enabled: true
21
+
22
+ Style/ExponentialNotation:
23
+ Enabled: true
24
+
25
+ Style/HashEachMethods:
26
+ Enabled: true
27
+
28
+ Style/HashTransformKeys:
29
+ Enabled: true
30
+
31
+ Style/HashTransformValues:
32
+ Enabled: true
33
+
34
+ Style/SlicingWithRange:
35
+ Enabled: true
36
+
37
+ Style/GlobalVars:
38
+ Enabled: false
39
+
40
+ Style/Documentation:
41
+ Enabled: false
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.5)
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,13 +17,18 @@ 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
23
28
 
24
29
  def refresh_cache!(args:, cache: nil)
25
30
  cache ||= Cache.new(args: args, options: self.class.cache_json_full_options)
26
- results = compute_results(args)
31
+ results = compute_results(**args)
27
32
  cache.cached_results = results
28
33
  results
29
34
  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.0'
4
+ VERSION = '1.2.5'
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,79 @@ 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
+ CacheJSON::Worker.perform_async(perm.to_json)
31
+ end
32
+ end
26
33
  end
27
34
  end
28
35
 
29
36
  private
30
37
 
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
38
+ def should_refresh?(klass, args)
39
+ !klass.new.check_cache(args: args) || klass.new.cache_expiring_soon?(args: args)
37
40
  end
38
41
 
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
42
+ class AllPermutations
43
+ def results
44
+ all_cache_classes.flat_map do |klass|
45
+ all_argument_permutations(klass).map do |args|
46
+ {
47
+ klass: klass,
48
+ args: args
49
+ }
50
+ end
51
+ end
43
52
  end
44
- end
45
53
 
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
- []
54
+ def all_cache_classes
55
+ # TODO: make this more efficient
56
+ ObjectSpace.each_object(Class).select do |klass|
57
+ klass.included_modules.include? CacheJSON::Base
58
+ end
52
59
  end
53
- end
54
60
 
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)
61
+ def all_argument_permutations(klass)
62
+ refresh_options = klass.cache_json_full_options[:refresh]
63
+ if refresh_options
64
+ all_combinations_with_fixed_points({}, refresh_options[:arguments])
65
+ else
66
+ []
64
67
  end
65
68
  end
66
- end
67
69
 
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]
70
+ def all_combinations_with_fixed_points(fixed_points, full_hash)
71
+ non_fixed_points = full_hash.dup.delete_if { |k, _| fixed_points.key?(k) }
72
+ if non_fixed_points.empty?
73
+ [fixed_points]
74
+ else
75
+ pivot_key = non_fixed_points.keys.first
76
+ values_for_key(non_fixed_points, pivot_key).flat_map do |pivot_key_value|
77
+ new_fixed_points = fixed_points.merge(Hash[pivot_key, pivot_key_value])
78
+ all_combinations_with_fixed_points(new_fixed_points, full_hash)
79
+ end
80
+ end
76
81
  end
77
- end
78
82
 
79
- def should_refresh?(klass, args)
80
- !klass.new.check_cache(args: args)
83
+ def values_for_key(hsh, key)
84
+ pivot_key_values = hsh[key]
85
+ if pivot_key_values.is_a?(Proc)
86
+ pivot_key_values.call
87
+ elsif pivot_key_values.is_a?(Range) || pivot_key_values.is_a?(Array)
88
+ pivot_key_values
89
+ else
90
+ [pivot_key_values]
91
+ end
92
+ end
81
93
  end
82
94
  end
83
95
  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.0
4
+ version: 1.2.5
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-03-02 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.0.3
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: []