redis-memo 0.1.1 → 1.1.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/lib/redis_memo.rb +48 -36
- data/lib/redis_memo/after_commit.rb +2 -2
- data/lib/redis_memo/batch.rb +36 -11
- data/lib/redis_memo/cache.rb +36 -19
- data/lib/redis_memo/connection_pool.rb +4 -3
- data/lib/redis_memo/errors.rb +9 -0
- data/lib/redis_memo/future.rb +22 -13
- data/lib/redis_memo/memoizable.rb +109 -72
- data/lib/redis_memo/memoizable/bump_version.lua +39 -0
- data/lib/redis_memo/memoizable/dependency.rb +10 -11
- data/lib/redis_memo/memoizable/invalidation.rb +68 -66
- data/lib/redis_memo/memoize_method.rb +169 -131
- data/lib/redis_memo/memoize_query.rb +135 -92
- data/lib/redis_memo/memoize_query/cached_select.rb +73 -62
- data/lib/redis_memo/memoize_query/cached_select/bind_params.rb +202 -70
- data/lib/redis_memo/memoize_query/cached_select/connection_adapter.rb +19 -10
- data/lib/redis_memo/memoize_query/invalidation.rb +22 -20
- data/lib/redis_memo/memoize_query/memoize_table_column.rb +1 -0
- data/lib/redis_memo/middleware.rb +3 -1
- data/lib/redis_memo/options.rb +111 -5
- data/lib/redis_memo/railtie.rb +11 -0
- data/lib/redis_memo/redis.rb +15 -5
- data/lib/redis_memo/testing.rb +49 -0
- data/lib/redis_memo/thread_local_var.rb +16 -0
- data/lib/redis_memo/tracer.rb +1 -0
- data/lib/redis_memo/util.rb +25 -0
- metadata +80 -4
@@ -1,119 +1,156 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'util'
|
4
|
+
|
5
|
+
# A +RedisMemo::Memoizable+ is a unit which represent a dependency on a memoized method.
|
6
|
+
# Dependencies can be declared recursively as a DAG (directed acyclic graph), meaning
|
7
|
+
# that a +RedisMemo::Memoizable+ object can have other +RedisMemo::Memoizable+ dependencies.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# memo = RedisMemo::Memoizable.new(a: 1) do
|
11
|
+
# depends_on RedisMemo::Memoizable.new(b: 3)
|
12
|
+
# depends_on RedisMemo::Memoizable.new(c: 4)
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# memoize_method :method_name do
|
16
|
+
# depends_on memo
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# RedisMemo will recursively extract all the dependencies in the DAG when computing a
|
20
|
+
# memoized method's versioned cache key.
|
3
21
|
class RedisMemo::Memoizable
|
4
22
|
require_relative 'memoizable/dependency'
|
5
23
|
require_relative 'memoizable/invalidation'
|
6
24
|
|
25
|
+
# @return [Hash] prop values on the current memoizable
|
7
26
|
attr_accessor :props
|
27
|
+
|
28
|
+
# @return [Proc] A proc representing other memoizables that this object depends on.
|
8
29
|
attr_reader :depends_on
|
9
30
|
|
31
|
+
# Creates a new +RedisMemo::Memoizable+ object.
|
32
|
+
#
|
33
|
+
# @param props [Hash]
|
34
|
+
# @yield depends_on A dependency block representing other +RedisMemo::Memoizable+s
|
35
|
+
# that this object depends on.
|
10
36
|
def initialize(**props, &depends_on)
|
11
37
|
@props = props
|
12
38
|
@depends_on = depends_on
|
13
39
|
@cache_key = nil
|
14
40
|
end
|
15
41
|
|
42
|
+
# Add extra props on the current RedisMemo::Memoizable+ object.
|
43
|
+
#
|
44
|
+
# @params args [Hash]
|
16
45
|
def extra_props(**args)
|
17
46
|
instance = dup
|
18
47
|
instance.props = props.dup.merge(**args)
|
19
48
|
instance
|
20
49
|
end
|
21
50
|
|
51
|
+
# Computes the checksum of the memoizable's prop values, and returns it as the cache key.
|
22
52
|
def cache_key
|
23
53
|
@cache_key ||= [
|
24
54
|
self.class.name,
|
25
|
-
RedisMemo.checksum(
|
26
|
-
RedisMemo.deep_sort_hash(@props).to_json,
|
55
|
+
RedisMemo::Util.checksum(
|
56
|
+
RedisMemo::Util.deep_sort_hash(@props).to_json,
|
27
57
|
),
|
28
58
|
].join(':')
|
29
59
|
end
|
30
60
|
|
31
|
-
#
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
cache_keys = instances.map(&:cache_key)
|
36
|
-
dependents_cache_keys += cache_keys
|
37
|
-
cache_keys
|
38
|
-
end
|
39
|
-
|
40
|
-
dependents_cache_keys.uniq!
|
41
|
-
dependents_versions = find_or_create_versions(dependents_cache_keys)
|
42
|
-
version_hash = dependents_cache_keys.zip(dependents_versions).to_h
|
43
|
-
|
44
|
-
cache_key_groups.map do |cache_keys|
|
45
|
-
RedisMemo.checksum(version_hash.slice(*cache_keys).to_json)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
61
|
+
# Invalidates the list of +RedisMemo::Memoizable+ objects by bumping the version stored
|
62
|
+
# in Redis.
|
63
|
+
#
|
64
|
+
# @param instances [Array[RedisMemo::Memoizable]]
|
49
65
|
def self.invalidate(instances)
|
50
66
|
instances.each do |instance|
|
51
67
|
cache_key = instance.cache_key
|
52
|
-
RedisMemo::Memoizable::Invalidation.
|
68
|
+
RedisMemo::Memoizable::Invalidation.__send__(
|
69
|
+
:bump_version_later,
|
53
70
|
cache_key,
|
54
|
-
RedisMemo.uuid,
|
71
|
+
RedisMemo::Util.uuid,
|
55
72
|
)
|
56
73
|
end
|
57
74
|
|
58
75
|
RedisMemo::Memoizable::Invalidation.drain_invalidation_queue
|
59
76
|
end
|
60
77
|
|
61
|
-
|
62
|
-
|
63
|
-
def self.find_or_create_versions(keys)
|
64
|
-
need_to_bump_versions = false
|
65
|
-
|
66
|
-
# Must check the local pending_memo_versions first in order to generate
|
67
|
-
# memo checksums. The pending_memo_versions are the expected versions that
|
68
|
-
# would be used if a transaction commited. With checksums consistent of
|
69
|
-
# pending versions, the method results would only be visible after a
|
70
|
-
# transaction commited (we bump the pending_memo_versions on redis as an
|
71
|
-
# after_commit callback)
|
72
|
-
if RedisMemo::AfterCommit.in_transaction?
|
73
|
-
memo_versions = RedisMemo::AfterCommit.pending_memo_versions.slice(*keys)
|
74
|
-
else
|
75
|
-
memo_versions = {}
|
76
|
-
end
|
78
|
+
class << self
|
79
|
+
private
|
77
80
|
|
78
|
-
|
79
|
-
|
81
|
+
def checksums(instances_groups)
|
82
|
+
dependents_cache_keys = []
|
83
|
+
cache_key_groups = instances_groups.map do |instances|
|
84
|
+
cache_keys = instances.map(&:cache_key)
|
85
|
+
dependents_cache_keys += cache_keys
|
86
|
+
cache_keys
|
87
|
+
end
|
80
88
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
raw: true,
|
88
|
-
raise_error: true,
|
89
|
-
)
|
89
|
+
dependents_cache_keys.uniq!
|
90
|
+
dependents_versions = find_or_create_versions(dependents_cache_keys)
|
91
|
+
version_hash = dependents_cache_keys.zip(dependents_versions).to_h
|
92
|
+
|
93
|
+
cache_key_groups.map do |cache_keys|
|
94
|
+
RedisMemo::Util.checksum(version_hash.slice(*cache_keys).to_json)
|
90
95
|
end
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
RedisMemo::
|
104
|
-
key,
|
105
|
-
new_version,
|
106
|
-
previous_version: '',
|
107
|
-
)
|
108
|
-
new_version
|
96
|
+
end
|
97
|
+
|
98
|
+
def find_or_create_versions(keys)
|
99
|
+
need_to_bump_versions = false
|
100
|
+
|
101
|
+
# Must check the local pending_memo_versions first in order to generate
|
102
|
+
# memo checksums. The pending_memo_versions are the expected versions that
|
103
|
+
# would be used if a transaction commited. With checksums consistent of
|
104
|
+
# pending versions, the method results would only be visible after a
|
105
|
+
# transaction commited (we bump the pending_memo_versions on redis as an
|
106
|
+
# after_commit callback)
|
107
|
+
if RedisMemo::AfterCommit.in_transaction?
|
108
|
+
memo_versions = RedisMemo::AfterCommit.pending_memo_versions.slice(*keys)
|
109
109
|
else
|
110
|
-
|
110
|
+
memo_versions = {}
|
111
|
+
end
|
112
|
+
|
113
|
+
keys_to_fetch = keys
|
114
|
+
keys_to_fetch -= memo_versions.keys unless memo_versions.empty?
|
115
|
+
|
116
|
+
cached_versions =
|
117
|
+
if keys_to_fetch.empty?
|
118
|
+
{}
|
119
|
+
else
|
120
|
+
RedisMemo::Cache.read_multi(
|
121
|
+
*keys_to_fetch,
|
122
|
+
raw: true,
|
123
|
+
raise_error: true,
|
124
|
+
)
|
125
|
+
end
|
126
|
+
memo_versions.merge!(cached_versions) unless cached_versions.empty?
|
127
|
+
|
128
|
+
versions = keys.map do |key|
|
129
|
+
version = memo_versions[key]
|
130
|
+
if version.nil?
|
131
|
+
# If a version does not exist, we assume it's because the version has
|
132
|
+
# expired due to TTL or it's evicted by a cache eviction policy. In
|
133
|
+
# this case, we will create a new version and use it for memoizing the
|
134
|
+
# cached result.
|
135
|
+
need_to_bump_versions = true
|
136
|
+
|
137
|
+
new_version = RedisMemo::Util.uuid
|
138
|
+
RedisMemo::Memoizable::Invalidation.__send__(
|
139
|
+
:bump_version_later,
|
140
|
+
key,
|
141
|
+
new_version,
|
142
|
+
previous_version: '',
|
143
|
+
)
|
144
|
+
new_version
|
145
|
+
else
|
146
|
+
version
|
147
|
+
end
|
111
148
|
end
|
112
|
-
end
|
113
149
|
|
114
|
-
|
115
|
-
|
150
|
+
# Flush out the versions to Redis (async) if we created new versions
|
151
|
+
RedisMemo::Memoizable::Invalidation.drain_invalidation_queue if need_to_bump_versions
|
116
152
|
|
117
|
-
|
153
|
+
versions
|
154
|
+
end
|
118
155
|
end
|
119
156
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
--[[
|
2
|
+
Script to bump the version of a memoizable's cache key.
|
3
|
+
|
4
|
+
RedisMemo can be used safely within transactions because it implements multi
|
5
|
+
version concurrency control (MVCC).
|
6
|
+
|
7
|
+
Before bumping dependency versions, RedisMemo will save its current version
|
8
|
+
prior to the update. While bumping the version on Redis, RedisMemo would check
|
9
|
+
if the current version still matches the expectation (in a Lua script to ensure atomicity).
|
10
|
+
If not, we would use a different version that has not been used before, thus
|
11
|
+
we have automatically invalidated the records that are being updated by overlapping
|
12
|
+
transactions.
|
13
|
+
|
14
|
+
Note: When Redis memory is full, bumping versions only works on Redis versions 6.x.
|
15
|
+
Prior versions of Redis have a bug in Lua where an OOM error is thrown instead of
|
16
|
+
eviction when Redis memory is full https://github.com/redis/redis/issues/6565
|
17
|
+
|
18
|
+
-- KEYS = cache_key
|
19
|
+
-- ARGV = [expected_prev_version desired_new_version version_on_mismatch ttl]
|
20
|
+
--]]
|
21
|
+
local key = KEYS[1]
|
22
|
+
local expected_prev_version,
|
23
|
+
desired_new_version,
|
24
|
+
version_on_mismatch,
|
25
|
+
ttl = unpack(ARGV)
|
26
|
+
|
27
|
+
local actual_prev_version = redis.call('get', key)
|
28
|
+
local new_version = version_on_mismatch
|
29
|
+
local px = {}
|
30
|
+
|
31
|
+
if (not actual_prev_version and expected_prev_version == '') or expected_prev_version == actual_prev_version then
|
32
|
+
new_version = desired_new_version
|
33
|
+
end
|
34
|
+
|
35
|
+
if ttl ~= '' then
|
36
|
+
px = {'px', ttl}
|
37
|
+
end
|
38
|
+
|
39
|
+
return redis.call('set', key, new_version, unpack(px))
|
@@ -12,13 +12,14 @@ class RedisMemo::Memoizable::Dependency
|
|
12
12
|
@nodes.values
|
13
13
|
end
|
14
14
|
|
15
|
-
def depends_on(dependency
|
15
|
+
def depends_on(dependency)
|
16
16
|
case dependency
|
17
17
|
when self.class
|
18
18
|
nodes.merge!(dependency.nodes)
|
19
19
|
when RedisMemo::Memoizable
|
20
20
|
memo = dependency
|
21
21
|
return if nodes.include?(memo.cache_key)
|
22
|
+
|
22
23
|
nodes[memo.cache_key] = memo
|
23
24
|
|
24
25
|
if memo.depends_on
|
@@ -29,7 +30,6 @@ class RedisMemo::Memoizable::Dependency
|
|
29
30
|
extracted = self.class.extract_from_relation(dependency)
|
30
31
|
nodes.merge!(extracted.nodes)
|
31
32
|
when RedisMemo::MemoizeQuery::CachedSelect::BindParams
|
32
|
-
# A private API
|
33
33
|
dependency.params.each do |model, attrs_set|
|
34
34
|
memo = model.redis_memo_class_memoizable
|
35
35
|
nodes[memo.cache_key] = memo
|
@@ -40,25 +40,24 @@ class RedisMemo::Memoizable::Dependency
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
else
|
43
|
-
raise(
|
44
|
-
RedisMemo::ArgumentError,
|
45
|
-
"Invalid dependency #{dependency}"
|
46
|
-
)
|
43
|
+
raise RedisMemo::ArgumentError.new("Invalid dependency #{dependency}")
|
47
44
|
end
|
48
45
|
end
|
49
46
|
|
50
|
-
private
|
51
|
-
|
52
47
|
def self.extract_from_relation(relation)
|
48
|
+
connection = ActiveRecord::Base.connection
|
49
|
+
unless connection.respond_to?(:dependency_of)
|
50
|
+
raise RedisMemo::WithoutMemoization.new('Caching active record queries is currently disabled on RedisMemo')
|
51
|
+
end
|
52
|
+
|
53
53
|
# Extract the dependent memos of an Arel without calling exec_query to actually execute the query
|
54
54
|
RedisMemo::MemoizeQuery::CachedSelect.with_new_query_context do
|
55
|
-
|
56
|
-
query, binds, _ = connection.send(:to_sql_and_binds, relation.arel)
|
55
|
+
query, binds, = connection.__send__(:to_sql_and_binds, relation.arel)
|
57
56
|
RedisMemo::MemoizeQuery::CachedSelect.current_query = relation.arel
|
58
57
|
is_query_cached = RedisMemo::MemoizeQuery::CachedSelect.extract_bind_params(query)
|
59
58
|
|
60
59
|
unless is_query_cached
|
61
|
-
raise RedisMemo::WithoutMemoization
|
60
|
+
raise RedisMemo::WithoutMemoization.new('Arel query is not cached using RedisMemo')
|
62
61
|
end
|
63
62
|
|
64
63
|
connection.dependency_of(:exec_query, query, nil, binds)
|
@@ -1,7 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'digest'
|
2
4
|
require_relative '../after_commit'
|
3
5
|
require_relative '../cache'
|
4
6
|
|
7
|
+
# Module containing the logic to perform invalidation on +RedisMemo::Memoizable+s.
|
5
8
|
module RedisMemo::Memoizable::Invalidation
|
6
9
|
class Task
|
7
10
|
attr_reader :key
|
@@ -44,36 +47,9 @@ module RedisMemo::Memoizable::Invalidation
|
|
44
47
|
# operations that triggered the invalidation has not yet happened.
|
45
48
|
@@invalidation_queue = Queue.new
|
46
49
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
local_cache = RedisMemo::Cache.local_cache
|
53
|
-
if previous_version.nil? && local_cache&.include?(key)
|
54
|
-
previous_version = local_cache[key]
|
55
|
-
elsif RedisMemo::AfterCommit.in_transaction?
|
56
|
-
# Fill an expected previous version so the later calculation results
|
57
|
-
# based on this version can still be rolled out if this version
|
58
|
-
# does not change
|
59
|
-
previous_version ||= RedisMemo::Cache.read_multi(
|
60
|
-
key,
|
61
|
-
raw: true,
|
62
|
-
)[key]
|
63
|
-
end
|
64
|
-
|
65
|
-
local_cache&.send(:[]=, key, version)
|
66
|
-
if RedisMemo::AfterCommit.in_transaction?
|
67
|
-
RedisMemo::AfterCommit.bump_memo_version_after_commit(
|
68
|
-
key,
|
69
|
-
version,
|
70
|
-
previous_version: previous_version,
|
71
|
-
)
|
72
|
-
else
|
73
|
-
@@invalidation_queue << Task.new(key, version, previous_version)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
50
|
+
# Drains the invalidation queue by bumping the versions of all memoizable cache
|
51
|
+
# keys currently in the queue. Performs invalidation asynchronously if an async
|
52
|
+
# handler is configured; otherwise, invaidation is done synchronously.
|
77
53
|
def self.drain_invalidation_queue
|
78
54
|
async_handler = RedisMemo::DefaultOptions.async
|
79
55
|
if async_handler.nil?
|
@@ -85,41 +61,15 @@ module RedisMemo::Memoizable::Invalidation
|
|
85
61
|
end
|
86
62
|
end
|
87
63
|
|
88
|
-
LUA_BUMP_VERSION =
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
version_on_mismatch,
|
93
|
-
ttl = unpack(ARGV)
|
94
|
-
|
95
|
-
local actual_prev_version = redis.call('get', key)
|
96
|
-
local new_version = version_on_mismatch
|
97
|
-
local px = {}
|
98
|
-
|
99
|
-
if (not actual_prev_version and expected_prev_version == '') or expected_prev_version == actual_prev_version then
|
100
|
-
new_version = desired_new_version
|
101
|
-
end
|
102
|
-
|
103
|
-
if ttl ~= '' then
|
104
|
-
px = {'px', ttl}
|
105
|
-
end
|
106
|
-
|
107
|
-
return redis.call('set', key, new_version, unpack(px))
|
108
|
-
LUA
|
109
|
-
|
110
|
-
def self.bump_version(task)
|
111
|
-
RedisMemo::Tracer.trace('redis_memo.memoizable.bump_version', task.key) do
|
112
|
-
ttl = RedisMemo::DefaultOptions.expires_in
|
113
|
-
ttl = (ttl * 1000.0).to_i if ttl
|
114
|
-
RedisMemo::Cache.redis.eval(
|
115
|
-
LUA_BUMP_VERSION,
|
116
|
-
keys: [task.key],
|
117
|
-
argv: [task.previous_version, task.version, RedisMemo.uuid, ttl],
|
118
|
-
)
|
119
|
-
RedisMemo::Tracer.set_tag(enqueue_to_finish: task.duration)
|
120
|
-
end
|
121
|
-
end
|
64
|
+
LUA_BUMP_VERSION = File.read(
|
65
|
+
File.join(File.dirname(__FILE__), 'bump_version.lua'),
|
66
|
+
)
|
67
|
+
private_constant :LUA_BUMP_VERSION
|
122
68
|
|
69
|
+
# Drains the invalidation queue synchronously by bumping the versions of all
|
70
|
+
# memoizable cache keys currently in the queue. If invalidation on a cache key
|
71
|
+
# fails due to transient Redis errors, the key is put back into the invalidation
|
72
|
+
# queue and retried on the next invalidation queue drain.
|
123
73
|
def self.drain_invalidation_queue_now
|
124
74
|
retry_queue = []
|
125
75
|
until @@invalidation_queue.empty?
|
@@ -127,16 +77,68 @@ module RedisMemo::Memoizable::Invalidation
|
|
127
77
|
begin
|
128
78
|
bump_version(task)
|
129
79
|
rescue SignalException, Redis::BaseConnectionError,
|
130
|
-
::ConnectionPool::TimeoutError
|
80
|
+
::ConnectionPool::TimeoutError => error
|
81
|
+
|
82
|
+
RedisMemo::DefaultOptions.redis_error_handler&.call(error, __method__)
|
83
|
+
RedisMemo::DefaultOptions.logger&.warn(error.full_message)
|
131
84
|
retry_queue << task
|
132
85
|
end
|
133
86
|
end
|
134
87
|
ensure
|
135
|
-
retry_queue.each { |
|
88
|
+
retry_queue.each { |t| @@invalidation_queue << t }
|
136
89
|
end
|
137
90
|
|
138
91
|
at_exit do
|
139
92
|
# The best effort
|
140
93
|
drain_invalidation_queue_now
|
141
94
|
end
|
95
|
+
|
96
|
+
class << self
|
97
|
+
private
|
98
|
+
|
99
|
+
def bump_version_later(key, version, previous_version: nil)
|
100
|
+
if RedisMemo::AfterCommit.in_transaction?
|
101
|
+
previous_version ||= RedisMemo::AfterCommit.pending_memo_versions[key]
|
102
|
+
end
|
103
|
+
|
104
|
+
local_cache = RedisMemo::Cache.local_cache
|
105
|
+
if previous_version.nil? && local_cache&.include?(key)
|
106
|
+
previous_version = local_cache[key]
|
107
|
+
elsif RedisMemo::AfterCommit.in_transaction?
|
108
|
+
# Fill an expected previous version so the later calculation results
|
109
|
+
# based on this version can still be rolled out if this version
|
110
|
+
# does not change
|
111
|
+
previous_version ||= RedisMemo::Cache.read_multi(
|
112
|
+
key,
|
113
|
+
raw: true,
|
114
|
+
)[key]
|
115
|
+
end
|
116
|
+
|
117
|
+
local_cache&.__send__(:[]=, key, version)
|
118
|
+
if RedisMemo::AfterCommit.in_transaction?
|
119
|
+
RedisMemo::AfterCommit.bump_memo_version_after_commit(
|
120
|
+
key,
|
121
|
+
version,
|
122
|
+
previous_version: previous_version,
|
123
|
+
)
|
124
|
+
else
|
125
|
+
@@invalidation_queue << Task.new(key, version, previous_version)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def bump_version(task)
|
130
|
+
RedisMemo::Tracer.trace('redis_memo.memoizable.bump_version', task.key) do
|
131
|
+
ttl = RedisMemo::DefaultOptions.expires_in
|
132
|
+
ttl = (ttl * 1000.0).to_i if ttl
|
133
|
+
@@bump_version_sha ||= Digest::SHA1.hexdigest(LUA_BUMP_VERSION)
|
134
|
+
RedisMemo::Cache.redis.run_script(
|
135
|
+
LUA_BUMP_VERSION,
|
136
|
+
@@bump_version_sha,
|
137
|
+
keys: [task.key],
|
138
|
+
argv: [task.previous_version, task.version, RedisMemo::Util.uuid, ttl],
|
139
|
+
)
|
140
|
+
RedisMemo::Tracer.set_tag(enqueue_to_finish: task.duration)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
142
144
|
end
|