redis 4.2.5 → 4.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/README.md +16 -11
- data/lib/redis/client.rb +23 -4
- data/lib/redis/cluster/node.rb +2 -1
- data/lib/redis/cluster/option.rb +5 -2
- data/lib/redis/cluster.rb +9 -13
- data/lib/redis/distributed.rb +13 -6
- data/lib/redis/version.rb +1 -1
- data/lib/redis.rb +119 -13
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d5ff2ee4b6a6f2b087ac26bf96a3c1769cf42f70ea90008361157f7ef04cdb14
|
4
|
+
data.tar.gz: f2c24654294c4fa81a5cff4ddb545bc59e6f85b64ee61273278cb1e286a4edb8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d88c6621659a178dca04d3ca62f25520f5f1a846b6300f93fb008966551fb4795a3e6c37810f99ea18f77a6292b955fa180ae3e06f8c90df7e6a3ca27087ae1
|
7
|
+
data.tar.gz: 1427cc268e867872388f214184d23a5c6062104fcb9d1e50d6026dd9daf6e51b9833866fee9fcf80c7a64e4de705295de8399d8e8ac22fa890bf358bd63ff707
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,22 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 4.4.0
|
4
|
+
|
5
|
+
* Redis cluster: fix cross-slot validation in pipelines. Fix ##1019.
|
6
|
+
* Add support for `XAUTOCLAIM`. See #1018.
|
7
|
+
* Properly issue `READONLY` when reconnecting to replicas. Fix #1017.
|
8
|
+
* Make `del` a noop if passed an empty list of keys. See #998.
|
9
|
+
* Add support for `ZINTER`. See #995.
|
10
|
+
|
11
|
+
# 4.3.1
|
12
|
+
|
13
|
+
* Fix password authentication against redis server 5 and older.
|
14
|
+
|
15
|
+
# 4.3.0
|
16
|
+
|
17
|
+
* Add the TYPE argument to scan and scan_each. See #985.
|
18
|
+
* Support AUTH command for ACL. See #967.
|
19
|
+
|
3
20
|
# 4.2.5
|
4
21
|
|
5
22
|
* Optimize the ruby connector write buffering. See #964.
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# redis-rb [![Build Status][
|
1
|
+
# redis-rb [![Build Status][gh-actions-image]][gh-actions-link] [![Inline docs][inchpages-image]][inchpages-link]
|
2
2
|
|
3
3
|
A Ruby client that tries to match [Redis][redis-home]' API one-to-one, while still
|
4
4
|
providing an idiomatic interface.
|
@@ -54,6 +54,12 @@ To connect to a password protected Redis instance, use:
|
|
54
54
|
redis = Redis.new(password: "mysecret")
|
55
55
|
```
|
56
56
|
|
57
|
+
To connect a Redis instance using [ACL](https://redis.io/topics/acl), use:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
redis = Redis.new(username: 'myname', password: 'mysecret')
|
61
|
+
```
|
62
|
+
|
57
63
|
The Redis class exports methods that are named identical to the commands
|
58
64
|
they execute. The arguments these methods accept are often identical to
|
59
65
|
the arguments specified on the [Redis website][redis-commands]. For
|
@@ -440,7 +446,7 @@ redis = Redis.new(:driver => :synchrony)
|
|
440
446
|
## Testing
|
441
447
|
|
442
448
|
This library is tested against recent Ruby and Redis versions.
|
443
|
-
Check [
|
449
|
+
Check [Github Actions][gh-actions-link] for the exact versions supported.
|
444
450
|
|
445
451
|
## See Also
|
446
452
|
|
@@ -459,12 +465,11 @@ client and evangelized Redis in Rubyland. Thank you, Ezra.
|
|
459
465
|
requests.
|
460
466
|
|
461
467
|
|
462
|
-
[inchpages-image]:
|
463
|
-
[inchpages-link]:
|
464
|
-
[redis-commands]:
|
465
|
-
[redis-home]:
|
466
|
-
[redis-url]:
|
467
|
-
[
|
468
|
-
[
|
469
|
-
[
|
470
|
-
[rubydoc]: http://www.rubydoc.info/gems/redis
|
468
|
+
[inchpages-image]: https://inch-ci.org/github/redis/redis-rb.svg
|
469
|
+
[inchpages-link]: https://inch-ci.org/github/redis/redis-rb
|
470
|
+
[redis-commands]: https://redis.io/commands
|
471
|
+
[redis-home]: https://redis.io
|
472
|
+
[redis-url]: http://www.iana.org/assignments/uri-schemes/prov/redis
|
473
|
+
[gh-actions-image]: https://github.com/redis/redis-rb/workflows/Test/badge.svg
|
474
|
+
[gh-actions-link]: https://github.com/redis/redis-rb/actions
|
475
|
+
[rubydoc]: http://www.rubydoc.info/gems/redis
|
data/lib/redis/client.rb
CHANGED
@@ -17,6 +17,7 @@ class Redis
|
|
17
17
|
write_timeout: nil,
|
18
18
|
connect_timeout: nil,
|
19
19
|
timeout: 5.0,
|
20
|
+
username: nil,
|
20
21
|
password: nil,
|
21
22
|
db: 0,
|
22
23
|
driver: nil,
|
@@ -61,6 +62,10 @@ class Redis
|
|
61
62
|
@options[:read_timeout]
|
62
63
|
end
|
63
64
|
|
65
|
+
def username
|
66
|
+
@options[:username]
|
67
|
+
end
|
68
|
+
|
64
69
|
def password
|
65
70
|
@options[:password]
|
66
71
|
end
|
@@ -110,7 +115,19 @@ class Redis
|
|
110
115
|
# Don't try to reconnect when the connection is fresh
|
111
116
|
with_reconnect(false) do
|
112
117
|
establish_connection
|
113
|
-
|
118
|
+
if password
|
119
|
+
if username
|
120
|
+
begin
|
121
|
+
call [:auth, username, password]
|
122
|
+
rescue CommandError # Likely on Redis < 6
|
123
|
+
call [:auth, password]
|
124
|
+
end
|
125
|
+
else
|
126
|
+
call [:auth, password]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
call [:readonly] if @options[:readonly]
|
114
131
|
call [:select, db] if db != 0
|
115
132
|
call [:client, :setname, @options[:id]] if @options[:id]
|
116
133
|
@connector.check(self)
|
@@ -131,7 +148,7 @@ class Redis
|
|
131
148
|
reply = process([command]) { read }
|
132
149
|
raise reply if reply.is_a?(CommandError)
|
133
150
|
|
134
|
-
if block_given?
|
151
|
+
if block_given? && reply != 'QUEUED'
|
135
152
|
yield reply
|
136
153
|
else
|
137
154
|
reply
|
@@ -434,7 +451,8 @@ class Redis
|
|
434
451
|
defaults[:scheme] = uri.scheme
|
435
452
|
defaults[:host] = uri.host if uri.host
|
436
453
|
defaults[:port] = uri.port if uri.port
|
437
|
-
defaults[:
|
454
|
+
defaults[:username] = CGI.unescape(uri.user) if uri.user && !uri.user.empty?
|
455
|
+
defaults[:password] = CGI.unescape(uri.password) if uri.password && !uri.password.empty?
|
438
456
|
defaults[:db] = uri.path[1..-1].to_i if uri.path
|
439
457
|
defaults[:role] = :master
|
440
458
|
else
|
@@ -510,7 +528,7 @@ class Redis
|
|
510
528
|
require_relative "connection/#{driver}"
|
511
529
|
rescue LoadError, NameError
|
512
530
|
begin
|
513
|
-
require "connection/#{driver}"
|
531
|
+
require "redis/connection/#{driver}"
|
514
532
|
rescue LoadError, NameError => error
|
515
533
|
raise "Cannot load driver #{driver.inspect}: #{error.message}"
|
516
534
|
end
|
@@ -579,6 +597,7 @@ class Redis
|
|
579
597
|
client = Client.new(@options.merge({
|
580
598
|
host: sentinel[:host] || sentinel["host"],
|
581
599
|
port: sentinel[:port] || sentinel["port"],
|
600
|
+
username: sentinel[:username] || sentinel["username"],
|
582
601
|
password: sentinel[:password] || sentinel["password"],
|
583
602
|
reconnect_attempts: 0
|
584
603
|
}))
|
data/lib/redis/cluster/node.rb
CHANGED
@@ -76,8 +76,9 @@ class Redis
|
|
76
76
|
clients = options.map do |node_key, option|
|
77
77
|
next if replica_disabled? && slave?(node_key)
|
78
78
|
|
79
|
+
option = option.merge(readonly: true) if slave?(node_key)
|
80
|
+
|
79
81
|
client = Client.new(option)
|
80
|
-
client.call(%i[readonly]) if slave?(node_key)
|
81
82
|
[node_key, client]
|
82
83
|
end
|
83
84
|
|
data/lib/redis/cluster/option.rb
CHANGED
@@ -18,6 +18,7 @@ class Redis
|
|
18
18
|
@node_opts = build_node_options(node_addrs)
|
19
19
|
@replica = options.delete(:replica) == true
|
20
20
|
add_common_node_option_if_needed(options, @node_opts, :scheme)
|
21
|
+
add_common_node_option_if_needed(options, @node_opts, :username)
|
21
22
|
add_common_node_option_if_needed(options, @node_opts, :password)
|
22
23
|
@options = options
|
23
24
|
end
|
@@ -63,7 +64,9 @@ class Redis
|
|
63
64
|
raise InvalidClientOptionError, "Invalid uri scheme #{addr}" unless VALID_SCHEMES.include?(uri.scheme)
|
64
65
|
|
65
66
|
db = uri.path.split('/')[1]&.to_i
|
66
|
-
|
67
|
+
|
68
|
+
{ scheme: uri.scheme, username: uri.user, password: uri.password, host: uri.host, port: uri.port, db: db }
|
69
|
+
.reject { |_, v| v.nil? || v == '' }
|
67
70
|
rescue URI::InvalidURIError => err
|
68
71
|
raise InvalidClientOptionError, err.message
|
69
72
|
end
|
@@ -79,7 +82,7 @@ class Redis
|
|
79
82
|
|
80
83
|
# Redis cluster node returns only host and port information.
|
81
84
|
# So we should complement additional information such as:
|
82
|
-
# scheme, password and so on.
|
85
|
+
# scheme, username, password and so on.
|
83
86
|
def add_common_node_option_if_needed(options, node_opts, key)
|
84
87
|
return options if options[key].nil? && node_opts.first[key].nil?
|
85
88
|
|
data/lib/redis/cluster.rb
CHANGED
@@ -78,11 +78,13 @@ class Redis
|
|
78
78
|
end
|
79
79
|
|
80
80
|
def call_pipeline(pipeline)
|
81
|
-
node_keys
|
82
|
-
|
81
|
+
node_keys = pipeline.commands.map { |cmd| find_node_key(cmd, primary_only: true) }.compact.uniq
|
82
|
+
if node_keys.size > 1
|
83
|
+
raise(CrossSlotPipeliningError,
|
84
|
+
pipeline.commands.map { |cmd| @command.extract_first_key(cmd) }.reject(&:empty?).uniq)
|
85
|
+
end
|
83
86
|
|
84
|
-
|
85
|
-
try_send(node, :call_pipeline, pipeline)
|
87
|
+
try_send(find_node(node_keys.first), :call_pipeline, pipeline)
|
86
88
|
end
|
87
89
|
|
88
90
|
def call_with_timeout(command, timeout, &block)
|
@@ -128,7 +130,7 @@ class Redis
|
|
128
130
|
def send_command(command, &block)
|
129
131
|
cmd = command.first.to_s.downcase
|
130
132
|
case cmd
|
131
|
-
when 'auth', 'bgrewriteaof', 'bgsave', 'quit', 'save'
|
133
|
+
when 'acl', 'auth', 'bgrewriteaof', 'bgsave', 'quit', 'save'
|
132
134
|
@node.call_all(command, &block).first
|
133
135
|
when 'flushall', 'flushdb'
|
134
136
|
@node.call_master(command, &block).first
|
@@ -253,14 +255,14 @@ class Redis
|
|
253
255
|
find_node(node_key)
|
254
256
|
end
|
255
257
|
|
256
|
-
def find_node_key(command)
|
258
|
+
def find_node_key(command, primary_only: false)
|
257
259
|
key = @command.extract_first_key(command)
|
258
260
|
return if key.empty?
|
259
261
|
|
260
262
|
slot = KeySlotConverter.convert(key)
|
261
263
|
return unless @slot.exists?(slot)
|
262
264
|
|
263
|
-
if @command.should_send_to_master?(command)
|
265
|
+
if @command.should_send_to_master?(command) || primary_only
|
264
266
|
@slot.find_node_key_of_master(slot)
|
265
267
|
else
|
266
268
|
@slot.find_node_key_of_slave(slot)
|
@@ -285,11 +287,5 @@ class Redis
|
|
285
287
|
@node.map(&:disconnect)
|
286
288
|
@node, @slot = fetch_cluster_info!(@option)
|
287
289
|
end
|
288
|
-
|
289
|
-
def extract_keys_in_pipeline(pipeline)
|
290
|
-
node_keys = pipeline.commands.map { |cmd| find_node_key(cmd) }.compact.uniq
|
291
|
-
command_keys = pipeline.commands.map { |cmd| @command.extract_first_key(cmd) }.reject(&:empty?)
|
292
|
-
[node_keys, command_keys]
|
293
|
-
end
|
294
290
|
end
|
295
291
|
end
|
data/lib/redis/distributed.rb
CHANGED
@@ -413,14 +413,14 @@ class Redis
|
|
413
413
|
node_for(key).rpushx(key, value)
|
414
414
|
end
|
415
415
|
|
416
|
-
# Remove and get the first
|
417
|
-
def lpop(key)
|
418
|
-
node_for(key).lpop(key)
|
416
|
+
# Remove and get the first elements in a list.
|
417
|
+
def lpop(key, count = nil)
|
418
|
+
node_for(key).lpop(key, count)
|
419
419
|
end
|
420
420
|
|
421
|
-
# Remove and get the last
|
422
|
-
def rpop(key)
|
423
|
-
node_for(key).rpop(key)
|
421
|
+
# Remove and get the last elements in a list.
|
422
|
+
def rpop(key, count = nil)
|
423
|
+
node_for(key).rpop(key, count)
|
424
424
|
end
|
425
425
|
|
426
426
|
# Remove the last element in a list, append it to another list and return
|
@@ -674,6 +674,13 @@ class Redis
|
|
674
674
|
node_for(key).zcount(key, min, max)
|
675
675
|
end
|
676
676
|
|
677
|
+
# Get the intersection of multiple sorted sets
|
678
|
+
def zinter(*keys, **options)
|
679
|
+
ensure_same_node(:zinter, keys) do |node|
|
680
|
+
node.zinter(*keys, **options)
|
681
|
+
end
|
682
|
+
end
|
683
|
+
|
677
684
|
# Intersect multiple sorted sets and store the resulting sorted set in a new
|
678
685
|
# key.
|
679
686
|
def zinterstore(destination, keys, **options)
|
data/lib/redis/version.rb
CHANGED
data/lib/redis.rb
CHANGED
@@ -39,6 +39,7 @@ class Redis
|
|
39
39
|
# @option options [String] :path path to server socket (overrides host and port)
|
40
40
|
# @option options [Float] :timeout (5.0) timeout in seconds
|
41
41
|
# @option options [Float] :connect_timeout (same as timeout) timeout for initial connect in seconds
|
42
|
+
# @option options [String] :username Username to authenticate against server
|
42
43
|
# @option options [String] :password Password to authenticate against server
|
43
44
|
# @option options [Integer] :db (0) Database to select after initial connect
|
44
45
|
# @option options [Symbol] :driver Driver to use, currently supported: `:ruby`, `:hiredis`, `:synchrony`
|
@@ -143,12 +144,13 @@ class Redis
|
|
143
144
|
|
144
145
|
# Authenticate to the server.
|
145
146
|
#
|
146
|
-
# @param [String]
|
147
|
-
#
|
147
|
+
# @param [Array<String>] args includes both username and password
|
148
|
+
# or only password
|
148
149
|
# @return [String] `OK`
|
149
|
-
|
150
|
+
# @see https://redis.io/commands/auth AUTH command
|
151
|
+
def auth(*args)
|
150
152
|
synchronize do |client|
|
151
|
-
client.call([:auth,
|
153
|
+
client.call([:auth, *args])
|
152
154
|
end
|
153
155
|
end
|
154
156
|
|
@@ -553,6 +555,9 @@ class Redis
|
|
553
555
|
# @param [String, Array<String>] keys
|
554
556
|
# @return [Integer] number of keys that were deleted
|
555
557
|
def del(*keys)
|
558
|
+
keys.flatten!(1)
|
559
|
+
return 0 if keys.empty?
|
560
|
+
|
556
561
|
synchronize do |client|
|
557
562
|
client.call([:del] + keys)
|
558
563
|
end
|
@@ -1170,23 +1175,29 @@ class Redis
|
|
1170
1175
|
end
|
1171
1176
|
end
|
1172
1177
|
|
1173
|
-
# Remove and get the first
|
1178
|
+
# Remove and get the first elements in a list.
|
1174
1179
|
#
|
1175
1180
|
# @param [String] key
|
1176
|
-
# @
|
1177
|
-
|
1181
|
+
# @param [Integer] count number of elements to remove
|
1182
|
+
# @return [String, Array<String>] the values of the first elements
|
1183
|
+
def lpop(key, count = nil)
|
1178
1184
|
synchronize do |client|
|
1179
|
-
|
1185
|
+
command = [:lpop, key]
|
1186
|
+
command << count if count
|
1187
|
+
client.call(command)
|
1180
1188
|
end
|
1181
1189
|
end
|
1182
1190
|
|
1183
|
-
# Remove and get the last
|
1191
|
+
# Remove and get the last elements in a list.
|
1184
1192
|
#
|
1185
1193
|
# @param [String] key
|
1186
|
-
# @
|
1187
|
-
|
1194
|
+
# @param [Integer] count number of elements to remove
|
1195
|
+
# @return [String, Array<String>] the values of the last elements
|
1196
|
+
def rpop(key, count = nil)
|
1188
1197
|
synchronize do |client|
|
1189
|
-
|
1198
|
+
command = [:rpop, key]
|
1199
|
+
command << count if count
|
1200
|
+
client.call(command)
|
1190
1201
|
end
|
1191
1202
|
end
|
1192
1203
|
|
@@ -2054,6 +2065,45 @@ class Redis
|
|
2054
2065
|
end
|
2055
2066
|
end
|
2056
2067
|
|
2068
|
+
# Return the intersection of multiple sorted sets
|
2069
|
+
#
|
2070
|
+
# @example Retrieve the intersection of `2*zsetA` and `1*zsetB`
|
2071
|
+
# redis.zinter("zsetA", "zsetB", :weights => [2.0, 1.0])
|
2072
|
+
# # => ["v1", "v2"]
|
2073
|
+
# @example Retrieve the intersection of `2*zsetA` and `1*zsetB`, and their scores
|
2074
|
+
# redis.zinter("zsetA", "zsetB", :weights => [2.0, 1.0], :with_scores => true)
|
2075
|
+
# # => [["v1", 3.0], ["v2", 6.0]]
|
2076
|
+
#
|
2077
|
+
# @param [String, Array<String>] keys one or more keys to intersect
|
2078
|
+
# @param [Hash] options
|
2079
|
+
# - `:weights => [Float, Float, ...]`: weights to associate with source
|
2080
|
+
# sorted sets
|
2081
|
+
# - `:aggregate => String`: aggregate function to use (sum, min, max, ...)
|
2082
|
+
# - `:with_scores => true`: include scores in output
|
2083
|
+
#
|
2084
|
+
# @return [Array<String>, Array<[String, Float]>]
|
2085
|
+
# - when `:with_scores` is not specified, an array of members
|
2086
|
+
# - when `:with_scores` is specified, an array with `[member, score]` pairs
|
2087
|
+
def zinter(*keys, weights: nil, aggregate: nil, with_scores: false)
|
2088
|
+
args = [:zinter, keys.size, *keys]
|
2089
|
+
|
2090
|
+
if weights
|
2091
|
+
args << "WEIGHTS"
|
2092
|
+
args.concat(weights)
|
2093
|
+
end
|
2094
|
+
|
2095
|
+
args << "AGGREGATE" << aggregate if aggregate
|
2096
|
+
|
2097
|
+
if with_scores
|
2098
|
+
args << "WITHSCORES"
|
2099
|
+
block = FloatifyPairs
|
2100
|
+
end
|
2101
|
+
|
2102
|
+
synchronize do |client|
|
2103
|
+
client.call(args, &block)
|
2104
|
+
end
|
2105
|
+
end
|
2106
|
+
|
2057
2107
|
# Intersect multiple sorted sets and store the resulting sorted set in a new
|
2058
2108
|
# key.
|
2059
2109
|
#
|
@@ -2636,12 +2686,13 @@ class Redis
|
|
2636
2686
|
_eval(:evalsha, args)
|
2637
2687
|
end
|
2638
2688
|
|
2639
|
-
def _scan(command, cursor, args, match: nil, count: nil, &block)
|
2689
|
+
def _scan(command, cursor, args, match: nil, count: nil, type: nil, &block)
|
2640
2690
|
# SSCAN/ZSCAN/HSCAN already prepend the key to +args+.
|
2641
2691
|
|
2642
2692
|
args << cursor
|
2643
2693
|
args << "MATCH" << match if match
|
2644
2694
|
args << "COUNT" << count if count
|
2695
|
+
args << "TYPE" << type if type
|
2645
2696
|
|
2646
2697
|
synchronize do |client|
|
2647
2698
|
client.call([command] + args, &block)
|
@@ -2656,11 +2707,15 @@ class Redis
|
|
2656
2707
|
# @example Retrieve a batch of keys matching a pattern
|
2657
2708
|
# redis.scan(4, :match => "key:1?")
|
2658
2709
|
# # => ["92", ["key:13", "key:18"]]
|
2710
|
+
# @example Retrieve a batch of keys of a certain type
|
2711
|
+
# redis.scan(92, :type => "zset")
|
2712
|
+
# # => ["173", ["sortedset:14", "sortedset:78"]]
|
2659
2713
|
#
|
2660
2714
|
# @param [String, Integer] cursor the cursor of the iteration
|
2661
2715
|
# @param [Hash] options
|
2662
2716
|
# - `:match => String`: only return keys matching the pattern
|
2663
2717
|
# - `:count => Integer`: return count keys at most per iteration
|
2718
|
+
# - `:type => String`: return keys only of the given type
|
2664
2719
|
#
|
2665
2720
|
# @return [String, Array<String>] the next cursor and all found keys
|
2666
2721
|
def scan(cursor, **options)
|
@@ -2676,10 +2731,15 @@ class Redis
|
|
2676
2731
|
# redis.scan_each(:match => "key:1?") {|key| puts key}
|
2677
2732
|
# # => key:13
|
2678
2733
|
# # => key:18
|
2734
|
+
# @example Execute block for each key of a type
|
2735
|
+
# redis.scan_each(:type => "hash") {|key| puts redis.type(key)}
|
2736
|
+
# # => "hash"
|
2737
|
+
# # => "hash"
|
2679
2738
|
#
|
2680
2739
|
# @param [Hash] options
|
2681
2740
|
# - `:match => String`: only return keys matching the pattern
|
2682
2741
|
# - `:count => Integer`: return count keys at most per iteration
|
2742
|
+
# - `:type => String`: return keys only of the given type
|
2683
2743
|
#
|
2684
2744
|
# @return [Enumerator] an enumerator for all found keys
|
2685
2745
|
def scan_each(**options, &block)
|
@@ -3220,6 +3280,38 @@ class Redis
|
|
3220
3280
|
synchronize { |client| client.call(args, &blk) }
|
3221
3281
|
end
|
3222
3282
|
|
3283
|
+
# Transfers ownership of pending stream entries that match the specified criteria.
|
3284
|
+
#
|
3285
|
+
# @example Claim next pending message stuck > 5 minutes and mark as retry
|
3286
|
+
# redis.xautoclaim('mystream', 'mygroup', 'consumer1', 3600000, '0-0')
|
3287
|
+
# @example Claim 50 next pending messages stuck > 5 minutes and mark as retry
|
3288
|
+
# redis.xclaim('mystream', 'mygroup', 'consumer1', 3600000, '0-0', count: 50)
|
3289
|
+
# @example Claim next pending message stuck > 5 minutes and don't mark as retry
|
3290
|
+
# redis.xclaim('mystream', 'mygroup', 'consumer1', 3600000, '0-0', justid: true)
|
3291
|
+
# @example Claim next pending message after this id stuck > 5 minutes and mark as retry
|
3292
|
+
# redis.xautoclaim('mystream', 'mygroup', 'consumer1', 3600000, '1641321233-0')
|
3293
|
+
#
|
3294
|
+
# @param key [String] the stream key
|
3295
|
+
# @param group [String] the consumer group name
|
3296
|
+
# @param consumer [String] the consumer name
|
3297
|
+
# @param min_idle_time [Integer] the number of milliseconds
|
3298
|
+
# @param start [String] entry id to start scanning from or 0-0 for everything
|
3299
|
+
# @param count [Integer] number of messages to claim (default 1)
|
3300
|
+
# @param justid [Boolean] whether to fetch just an array of entry ids or not.
|
3301
|
+
# Does not increment retry count when true
|
3302
|
+
#
|
3303
|
+
# @return [Hash{String => Hash}] the entries successfully claimed
|
3304
|
+
# @return [Array<String>] the entry ids successfully claimed if justid option is `true`
|
3305
|
+
def xautoclaim(key, group, consumer, min_idle_time, start, count: nil, justid: false)
|
3306
|
+
args = [:xautoclaim, key, group, consumer, min_idle_time, start]
|
3307
|
+
if count
|
3308
|
+
args << 'COUNT' << count.to_s
|
3309
|
+
end
|
3310
|
+
args << 'JUSTID' if justid
|
3311
|
+
blk = justid ? HashifyStreamAutoclaimJustId : HashifyStreamAutoclaim
|
3312
|
+
synchronize { |client| client.call(args, &blk) }
|
3313
|
+
end
|
3314
|
+
|
3223
3315
|
# Fetches not acknowledging pending entries
|
3224
3316
|
#
|
3225
3317
|
# @example With key and group
|
@@ -3430,6 +3522,20 @@ class Redis
|
|
3430
3522
|
end
|
3431
3523
|
}
|
3432
3524
|
|
3525
|
+
HashifyStreamAutoclaim = lambda { |reply|
|
3526
|
+
{
|
3527
|
+
'next' => reply[0],
|
3528
|
+
'entries' => reply[1].map { |entry| [entry[0], entry[1].each_slice(2).to_h] }
|
3529
|
+
}
|
3530
|
+
}
|
3531
|
+
|
3532
|
+
HashifyStreamAutoclaimJustId = lambda { |reply|
|
3533
|
+
{
|
3534
|
+
'next' => reply[0],
|
3535
|
+
'entries' => reply[1]
|
3536
|
+
}
|
3537
|
+
}
|
3538
|
+
|
3433
3539
|
HashifyStreamPendings = lambda { |reply|
|
3434
3540
|
{
|
3435
3541
|
'size' => reply[0],
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ezra Zygmuntowicz
|
@@ -16,7 +16,7 @@ authors:
|
|
16
16
|
autorequire:
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
|
-
date:
|
19
|
+
date: 2021-07-28 00:00:00.000000000 Z
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
22
|
name: em-synchrony
|
@@ -102,9 +102,9 @@ licenses:
|
|
102
102
|
metadata:
|
103
103
|
bug_tracker_uri: https://github.com/redis/redis-rb/issues
|
104
104
|
changelog_uri: https://github.com/redis/redis-rb/blob/master/CHANGELOG.md
|
105
|
-
documentation_uri: https://www.rubydoc.info/gems/redis/4.
|
105
|
+
documentation_uri: https://www.rubydoc.info/gems/redis/4.4.0
|
106
106
|
homepage_uri: https://github.com/redis/redis-rb
|
107
|
-
source_code_uri: https://github.com/redis/redis-rb/tree/v4.
|
107
|
+
source_code_uri: https://github.com/redis/redis-rb/tree/v4.4.0
|
108
108
|
post_install_message:
|
109
109
|
rdoc_options: []
|
110
110
|
require_paths:
|