redis-memo 0.0.0.beta.3 → 0.0.0.beta.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/redis_memo.rb +1 -0
- data/lib/redis_memo/cache.rb +9 -3
- data/lib/redis_memo/connection_pool.rb +27 -0
- data/lib/redis_memo/future.rb +3 -3
- data/lib/redis_memo/memoizable.rb +5 -1
- data/lib/redis_memo/memoizable/dependency.rb +2 -2
- data/lib/redis_memo/memoizable/invalidation.rb +6 -2
- data/lib/redis_memo/memoize_method.rb +12 -7
- data/lib/redis_memo/memoize_query.rb +6 -2
- data/lib/redis_memo/memoize_query/cached_select.rb +33 -3
- data/lib/redis_memo/memoize_query/invalidation.rb +64 -25
- data/lib/redis_memo/options.rb +17 -18
- metadata +24 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72bcf0679b811825222a6b38de0fcdadf4546640d2f61b18ebc827e37137dc41
|
4
|
+
data.tar.gz: 7a55c7bbd084a24afe085e85bc5cd5c486cf240094b64ca09d48e9e0ce126384
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a3af887512e4b6571829fcfda719e43abb917eb4773407bd27788b0b671a42263ec31c2f6286f0a1279a354851c8c8cb48eb9701cba59863e500ca47419080e
|
7
|
+
data.tar.gz: feeb72b177ec07953b839e6e0759cbdf42dfd4eddd19f89599e721589462e849e7685a659b03128504d670764223f1805402cb3ee8a96411b834f229ba837d99
|
data/lib/redis_memo.rb
CHANGED
data/lib/redis_memo/cache.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require_relative 'options'
|
3
3
|
require_relative 'redis'
|
4
|
+
require_relative 'connection_pool'
|
4
5
|
|
5
6
|
class RedisMemo::Cache < ActiveSupport::Cache::RedisCacheStore
|
6
7
|
class Rescuable < Exception; end
|
@@ -24,7 +25,12 @@ class RedisMemo::Cache < ActiveSupport::Cache::RedisCacheStore
|
|
24
25
|
end
|
25
26
|
|
26
27
|
def self.redis
|
27
|
-
@@redis ||=
|
28
|
+
@@redis ||=
|
29
|
+
if RedisMemo::DefaultOptions.connection_pool
|
30
|
+
RedisMemo::ConnectionPool.new(**RedisMemo::DefaultOptions.connection_pool)
|
31
|
+
else
|
32
|
+
RedisMemo::DefaultOptions.redis
|
33
|
+
end
|
28
34
|
end
|
29
35
|
|
30
36
|
def self.redis_store
|
@@ -60,7 +66,7 @@ class RedisMemo::Cache < ActiveSupport::Cache::RedisCacheStore
|
|
60
66
|
end
|
61
67
|
|
62
68
|
# RedisCacheStore doesn't read from the local cache before reading from redis
|
63
|
-
def read_multi(*keys, raise_error: false)
|
69
|
+
def read_multi(*keys, raw: false, raise_error: false)
|
64
70
|
return {} if keys.empty?
|
65
71
|
|
66
72
|
Thread.current[THREAD_KEY_RAISE_ERROR] = raise_error
|
@@ -71,7 +77,7 @@ class RedisMemo::Cache < ActiveSupport::Cache::RedisCacheStore
|
|
71
77
|
keys_to_fetch -= local_entries.keys unless local_entries.empty?
|
72
78
|
return local_entries if keys_to_fetch.empty?
|
73
79
|
|
74
|
-
remote_entries = redis_store.read_multi(*keys_to_fetch)
|
80
|
+
remote_entries = redis_store.read_multi(*keys_to_fetch, raw: raw)
|
75
81
|
local_cache&.merge!(remote_entries)
|
76
82
|
|
77
83
|
if local_entries.empty?
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'connection_pool'
|
3
|
+
require_relative 'redis'
|
4
|
+
|
5
|
+
class RedisMemo::ConnectionPool
|
6
|
+
def initialize(**options)
|
7
|
+
@connection_pool = ::ConnectionPool.new(**options) do
|
8
|
+
# Construct a new client every time the block gets called
|
9
|
+
RedisMemo::Redis.new(RedisMemo::DefaultOptions.redis_config)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Avoid method_missing when possible for better performance
|
14
|
+
%i(get mget mapped_mget set eval).each do |method_name|
|
15
|
+
define_method method_name do |*args, &blk|
|
16
|
+
@connection_pool.with do |redis|
|
17
|
+
redis.send(method_name, *args, &blk)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def method_missing(method_name, *args, &blk)
|
23
|
+
@connection_pool.with do |redis|
|
24
|
+
redis.send(method_name, *args, &blk)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/redis_memo/future.rb
CHANGED
@@ -9,14 +9,14 @@ class RedisMemo::Future
|
|
9
9
|
ref,
|
10
10
|
method_id,
|
11
11
|
method_args,
|
12
|
-
|
12
|
+
dependent_memos,
|
13
13
|
cache_options,
|
14
14
|
method_name_without_memo
|
15
15
|
)
|
16
16
|
@ref = ref
|
17
17
|
@method_id = method_id
|
18
18
|
@method_args = method_args
|
19
|
-
@
|
19
|
+
@dependent_memos = dependent_memos
|
20
20
|
@cache_options = cache_options
|
21
21
|
@method_name_without_memo = method_name_without_memo
|
22
22
|
@method_cache_key = nil
|
@@ -28,7 +28,7 @@ class RedisMemo::Future
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def context
|
31
|
-
[@
|
31
|
+
[@method_id, @method_args, @dependent_memos]
|
32
32
|
end
|
33
33
|
|
34
34
|
def method_cache_key
|
@@ -82,7 +82,11 @@ class RedisMemo::Memoizable
|
|
82
82
|
if keys_to_fetch.empty?
|
83
83
|
{}
|
84
84
|
else
|
85
|
-
RedisMemo::Cache.read_multi(
|
85
|
+
RedisMemo::Cache.read_multi(
|
86
|
+
*keys_to_fetch,
|
87
|
+
raw: true,
|
88
|
+
raise_error: true,
|
89
|
+
)
|
86
90
|
end
|
87
91
|
memo_versions.merge!(cached_versions) unless cached_versions.empty?
|
88
92
|
|
@@ -51,8 +51,8 @@ class RedisMemo::Memoizable::Dependency
|
|
51
51
|
RedisMemo::MemoizeQuery::CachedSelect.current_query = relation.arel
|
52
52
|
is_query_cached = RedisMemo::MemoizeQuery::CachedSelect.extract_bind_params(query)
|
53
53
|
raise(
|
54
|
-
RedisMemo::
|
55
|
-
"
|
54
|
+
RedisMemo::WithoutMemoization,
|
55
|
+
"Arel query is not cached using RedisMemo."
|
56
56
|
) unless is_query_cached
|
57
57
|
extracted_dependency = connection.dependency_of(:exec_query, query, nil, binds)
|
58
58
|
end
|
@@ -56,7 +56,10 @@ module RedisMemo::Memoizable::Invalidation
|
|
56
56
|
# Fill an expected previous version so the later calculation results
|
57
57
|
# based on this version can still be rolled out if this version
|
58
58
|
# does not change
|
59
|
-
previous_version ||= RedisMemo::Cache.read_multi(
|
59
|
+
previous_version ||= RedisMemo::Cache.read_multi(
|
60
|
+
key,
|
61
|
+
raw: true,
|
62
|
+
)[key]
|
60
63
|
end
|
61
64
|
|
62
65
|
local_cache&.send(:[]=, key, version)
|
@@ -123,7 +126,8 @@ module RedisMemo::Memoizable::Invalidation
|
|
123
126
|
task = @@invalidation_queue.pop
|
124
127
|
begin
|
125
128
|
bump_version(task)
|
126
|
-
rescue SignalException, Redis::BaseConnectionError
|
129
|
+
rescue SignalException, Redis::BaseConnectionError,
|
130
|
+
::ConnectionPool::TimeoutError
|
127
131
|
retry_queue << task
|
128
132
|
end
|
129
133
|
end
|
@@ -15,6 +15,12 @@ module RedisMemo::MemoizeMethod
|
|
15
15
|
define_method method_name_with_memo do |*args|
|
16
16
|
return send(method_name_without_memo, *args) if RedisMemo.without_memo?
|
17
17
|
|
18
|
+
dependent_memos = nil
|
19
|
+
if depends_on
|
20
|
+
dependency = RedisMemo::MemoizeMethod.get_or_extract_dependencies(self, *args, &depends_on)
|
21
|
+
dependent_memos = dependency.memos
|
22
|
+
end
|
23
|
+
|
18
24
|
future = RedisMemo::Future.new(
|
19
25
|
self,
|
20
26
|
case method_id
|
@@ -26,7 +32,7 @@ module RedisMemo::MemoizeMethod
|
|
26
32
|
method_id.call(self, *args)
|
27
33
|
end,
|
28
34
|
args,
|
29
|
-
|
35
|
+
dependent_memos,
|
30
36
|
options,
|
31
37
|
method_name_without_memo,
|
32
38
|
)
|
@@ -37,6 +43,8 @@ module RedisMemo::MemoizeMethod
|
|
37
43
|
end
|
38
44
|
|
39
45
|
future.execute
|
46
|
+
rescue RedisMemo::WithoutMemoization
|
47
|
+
send(method_name_without_memo, *args)
|
40
48
|
end
|
41
49
|
|
42
50
|
alias_method method_name, method_name_with_memo
|
@@ -83,17 +91,14 @@ module RedisMemo::MemoizeMethod
|
|
83
91
|
|
84
92
|
def self.method_cache_keys(future_contexts)
|
85
93
|
memos = Array.new(future_contexts.size)
|
86
|
-
future_contexts.each_with_index do |(
|
87
|
-
|
88
|
-
dependency = get_or_extract_dependencies(ref, *method_args, &depends_on)
|
89
|
-
memos[i] = dependency.memos
|
90
|
-
end
|
94
|
+
future_contexts.each_with_index do |(_, _, dependent_memos), i|
|
95
|
+
memos[i] = dependent_memos
|
91
96
|
end
|
92
97
|
|
93
98
|
j = 0
|
94
99
|
memo_checksums = RedisMemo::Memoizable.checksums(memos.compact)
|
95
100
|
method_cache_key_versions = Array.new(future_contexts.size)
|
96
|
-
future_contexts.each_with_index do |(
|
101
|
+
future_contexts.each_with_index do |(method_id, method_args, _), i|
|
97
102
|
if memos[i]
|
98
103
|
method_cache_key_versions[i] = [method_id, memo_checksums[j]]
|
99
104
|
j += 1
|
@@ -13,6 +13,8 @@ if defined?(ActiveRecord)
|
|
13
13
|
# after each record save
|
14
14
|
def memoize_table_column(*raw_columns, editable: true)
|
15
15
|
RedisMemo::MemoizeQuery.using_active_record!(self)
|
16
|
+
return if ENV["REDIS_MEMO_DISABLE_#{self.table_name.upcase}"] == 'true'
|
17
|
+
|
16
18
|
columns = raw_columns.map(&:to_sym).sort
|
17
19
|
|
18
20
|
RedisMemo::MemoizeQuery.memoized_columns(self, editable_only: true) << columns if editable
|
@@ -102,8 +104,10 @@ if defined?(ActiveRecord)
|
|
102
104
|
end
|
103
105
|
end
|
104
106
|
|
105
|
-
def self.invalidate(
|
106
|
-
RedisMemo::Memoizable.invalidate(
|
107
|
+
def self.invalidate(*records)
|
108
|
+
RedisMemo::Memoizable.invalidate(
|
109
|
+
records.map { |record| to_memos(record) }.flatten,
|
110
|
+
)
|
107
111
|
end
|
108
112
|
|
109
113
|
def self.to_memos(record)
|
@@ -123,7 +123,14 @@ class RedisMemo::MemoizeQuery::CachedSelect
|
|
123
123
|
|
124
124
|
depends_on RedisMemo::Memoizable.new(
|
125
125
|
__redis_memo_memoize_query_memoize_query_sql__: sql,
|
126
|
-
__redis_memo_memoize_query_memoize_query_binds__: binds.map
|
126
|
+
__redis_memo_memoize_query_memoize_query_binds__: binds.map do |bind|
|
127
|
+
if bind.respond_to?(:value_for_database)
|
128
|
+
bind.value_for_database
|
129
|
+
else
|
130
|
+
# In activerecord >= 6, a bind could be an actual database value
|
131
|
+
bind
|
132
|
+
end
|
133
|
+
end
|
127
134
|
)
|
128
135
|
end
|
129
136
|
end
|
@@ -210,7 +217,7 @@ class RedisMemo::MemoizeQuery::CachedSelect
|
|
210
217
|
bind_params = BindParams.new
|
211
218
|
|
212
219
|
case node
|
213
|
-
when
|
220
|
+
when NodeHasFilterCondition
|
214
221
|
attr_node = node.left
|
215
222
|
return unless attr_node.is_a?(Arel::Attributes::Attribute)
|
216
223
|
|
@@ -247,7 +254,13 @@ class RedisMemo::MemoizeQuery::CachedSelect
|
|
247
254
|
}
|
248
255
|
when Arel::Nodes::Casted
|
249
256
|
bind_params.params[binding_relation] << {
|
250
|
-
right.attribute.name.to_sym =>
|
257
|
+
right.attribute.name.to_sym =>
|
258
|
+
if right.respond_to?(:val)
|
259
|
+
right.val
|
260
|
+
else
|
261
|
+
# activerecord >= 6
|
262
|
+
right.value
|
263
|
+
end,
|
251
264
|
}
|
252
265
|
else
|
253
266
|
bind_params = bind_params.union(extract_bind_params_recurse(right))
|
@@ -343,6 +356,23 @@ class RedisMemo::MemoizeQuery::CachedSelect
|
|
343
356
|
enabled_models[table_node.try(:name)]
|
344
357
|
end
|
345
358
|
|
359
|
+
class NodeHasFilterCondition
|
360
|
+
def self.===(node)
|
361
|
+
case node
|
362
|
+
when Arel::Nodes::Equality, Arel::Nodes::In
|
363
|
+
true
|
364
|
+
else
|
365
|
+
# In activerecord >= 6, a new arel node HomogeneousIn is introduced
|
366
|
+
if defined?(Arel::Nodes::HomogeneousIn) &&
|
367
|
+
node.is_a?(Arel::Nodes::HomogeneousIn)
|
368
|
+
true
|
369
|
+
else
|
370
|
+
false
|
371
|
+
end
|
372
|
+
end
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
346
376
|
# Thread locals to exchange information between RedisMemo and ActiveRecord
|
347
377
|
THREAD_KEY_AREL = :__redis_memo_memoize_query_cached_select_arel__
|
348
378
|
THREAD_KEY_SUBSTITUTES = :__redis_memo_memoize_query_cached_select_substitues__
|
@@ -110,9 +110,9 @@ class RedisMemo::MemoizeQuery::Invalidation
|
|
110
110
|
define_method method_name do |*args, &blk|
|
111
111
|
options = args.last.is_a?(Hash) ? args.last : {}
|
112
112
|
records = args[args.last.is_a?(Hash) ? -2 : -1]
|
113
|
-
|
114
|
-
if
|
115
|
-
|
113
|
+
columns_to_update = options[:on_duplicate_key_update]
|
114
|
+
if columns_to_update.is_a?(Hash)
|
115
|
+
columns_to_update = columns_to_update[:columns]
|
116
116
|
end
|
117
117
|
|
118
118
|
if records.last.is_a?(Hash)
|
@@ -123,11 +123,11 @@ class RedisMemo::MemoizeQuery::Invalidation
|
|
123
123
|
# - default values filled by the database
|
124
124
|
# - updates on conflict conditions
|
125
125
|
records_to_invalidate =
|
126
|
-
if
|
126
|
+
if columns_to_update
|
127
127
|
RedisMemo::MemoizeQuery::Invalidation.send(
|
128
|
-
:
|
128
|
+
:select_by_columns,
|
129
129
|
records,
|
130
|
-
|
130
|
+
columns_to_update,
|
131
131
|
)
|
132
132
|
else
|
133
133
|
[]
|
@@ -135,38 +135,77 @@ class RedisMemo::MemoizeQuery::Invalidation
|
|
135
135
|
|
136
136
|
result = send(:"#{method_name}_without_redis_memo_invalidation", *args, &blk)
|
137
137
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
138
|
+
# Offload the records to invalidate while selecting the next set of
|
139
|
+
# records to invalidate
|
140
|
+
case records_to_invalidate
|
141
|
+
when Array
|
142
|
+
RedisMemo::MemoizeQuery.invalidate(*records_to_invalidate) unless records_to_invalidate.empty?
|
143
|
+
|
144
|
+
RedisMemo::MemoizeQuery.invalidate(*RedisMemo::MemoizeQuery::Invalidation.send(
|
145
|
+
:select_by_id,
|
146
|
+
model_class,
|
147
|
+
# Not all databases support "RETURNING", which is useful when
|
148
|
+
# invaldating records after bulk creation
|
149
|
+
result.ids,
|
150
|
+
))
|
151
|
+
else
|
152
|
+
RedisMemo::MemoizeQuery.invalidate_all(model_class)
|
142
153
|
end
|
143
154
|
|
144
|
-
memos_to_invalidate = records_to_invalidate.map do |record|
|
145
|
-
RedisMemo::MemoizeQuery.to_memos(record)
|
146
|
-
end
|
147
|
-
RedisMemo::Memoizable.invalidate(memos_to_invalidate.flatten)
|
148
|
-
|
149
155
|
result
|
150
156
|
end
|
151
157
|
end
|
152
158
|
end
|
153
159
|
|
154
|
-
def self.
|
160
|
+
def self.select_by_columns(records, columns_to_update)
|
155
161
|
model_class = records.first.class
|
156
162
|
or_chain = nil
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
163
|
+
columns_to_select = columns_to_update & RedisMemo::MemoizeQuery
|
164
|
+
.memoized_columns(model_class)
|
165
|
+
.to_a.flatten.uniq
|
166
|
+
|
167
|
+
# Nothing to invalidate here
|
168
|
+
return [] if columns_to_select.empty?
|
169
|
+
|
170
|
+
RedisMemo::Tracer.trace(
|
171
|
+
'redis_memo.memoize_query.invalidation',
|
172
|
+
"#{__method__}##{model_class.name}",
|
173
|
+
) do
|
174
|
+
records.each do |record|
|
175
|
+
conditions = {}
|
176
|
+
columns_to_select.each do |column|
|
177
|
+
conditions[column] = record.send(column)
|
178
|
+
end
|
179
|
+
if or_chain
|
180
|
+
or_chain = or_chain.or(model_class.where(conditions))
|
181
|
+
else
|
182
|
+
or_chain = model_class.where(conditions)
|
183
|
+
end
|
162
184
|
end
|
163
|
-
|
164
|
-
|
185
|
+
|
186
|
+
record_count = RedisMemo.without_memo { or_chain.count }
|
187
|
+
if record_count > bulk_operations_invalidation_limit
|
188
|
+
nil
|
165
189
|
else
|
166
|
-
|
190
|
+
RedisMemo.without_memo { or_chain.to_a }
|
167
191
|
end
|
168
192
|
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def self.select_by_id(model_class, ids)
|
196
|
+
RedisMemo::Tracer.trace(
|
197
|
+
'redis_memo.memoize_query.invalidation',
|
198
|
+
"#{__method__}##{model_class.name}",
|
199
|
+
) do
|
200
|
+
RedisMemo.without_memo do
|
201
|
+
model_class.where(model_class.primary_key => ids).to_a
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
169
205
|
|
170
|
-
|
206
|
+
def self.bulk_operations_invalidation_limit
|
207
|
+
ENV['REDIS_MEMO_BULK_OPERATIONS_INVALIDATION_LIMIT']&.to_i ||
|
208
|
+
RedisMemo::DefaultOptions.bulk_operations_invalidation_limit ||
|
209
|
+
10000
|
171
210
|
end
|
172
211
|
end
|
data/lib/redis_memo/options.rb
CHANGED
@@ -13,7 +13,7 @@ class RedisMemo::Options
|
|
13
13
|
)
|
14
14
|
@compress = compress.nil? ? true : compress
|
15
15
|
@compress_threshold = compress_threshold || 1.kilobyte
|
16
|
-
@
|
16
|
+
@redis_config = redis
|
17
17
|
@redis_client = nil
|
18
18
|
@redis_error_handler = redis_error_handler
|
19
19
|
@tracer = tracer
|
@@ -22,20 +22,18 @@ class RedisMemo::Options
|
|
22
22
|
@expires_in = expires_in
|
23
23
|
end
|
24
24
|
|
25
|
-
def redis
|
26
|
-
|
27
|
-
|
25
|
+
def redis
|
26
|
+
@redis_client ||= RedisMemo::Redis.new(redis_config)
|
27
|
+
end
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
@redis = blk
|
38
|
-
end
|
29
|
+
def redis_config
|
30
|
+
@redis_config || {}
|
31
|
+
end
|
32
|
+
|
33
|
+
def redis=(config)
|
34
|
+
@redis_config = config
|
35
|
+
@redis_client = nil
|
36
|
+
redis
|
39
37
|
end
|
40
38
|
|
41
39
|
def tracer(&blk)
|
@@ -74,15 +72,16 @@ class RedisMemo::Options
|
|
74
72
|
end
|
75
73
|
|
76
74
|
attr_accessor :async
|
75
|
+
attr_accessor :bulk_operations_invalidation_limit
|
76
|
+
attr_accessor :cache_out_of_date_handler
|
77
|
+
attr_accessor :cache_validation_sampler
|
77
78
|
attr_accessor :compress
|
78
79
|
attr_accessor :compress_threshold
|
79
|
-
attr_accessor :
|
80
|
+
attr_accessor :connection_pool
|
80
81
|
attr_accessor :expires_in
|
81
|
-
attr_accessor :
|
82
|
-
attr_accessor :cache_out_of_date_handler
|
82
|
+
attr_accessor :redis_error_handler
|
83
83
|
|
84
84
|
attr_writer :global_cache_key_version
|
85
|
-
attr_writer :redis
|
86
85
|
attr_writer :tracer
|
87
86
|
attr_writer :logger
|
88
87
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-memo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.0.beta.
|
4
|
+
version: 0.0.0.beta.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chan Zuckerberg Initiative
|
@@ -14,42 +14,56 @@ dependencies:
|
|
14
14
|
name: activesupport
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '5.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '5.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: redis
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 4.0.1
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 4.0.1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: connection_pool
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 2.2.3
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.2.3
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: activerecord
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
|
-
- - "
|
59
|
+
- - ">="
|
46
60
|
- !ruby/object:Gem::Version
|
47
61
|
version: '5.2'
|
48
62
|
type: :development
|
49
63
|
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
|
-
- - "
|
66
|
+
- - ">="
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: '5.2'
|
55
69
|
- !ruby/object:Gem::Dependency
|
@@ -161,6 +175,7 @@ files:
|
|
161
175
|
- lib/redis_memo/after_commit.rb
|
162
176
|
- lib/redis_memo/batch.rb
|
163
177
|
- lib/redis_memo/cache.rb
|
178
|
+
- lib/redis_memo/connection_pool.rb
|
164
179
|
- lib/redis_memo/future.rb
|
165
180
|
- lib/redis_memo/memoizable.rb
|
166
181
|
- lib/redis_memo/memoizable/dependency.rb
|