redis 4.2.2 → 4.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -0
- data/README.md +17 -11
- data/lib/redis.rb +40 -24
- data/lib/redis/client.rb +26 -4
- data/lib/redis/cluster.rb +1 -1
- data/lib/redis/cluster/option.rb +5 -2
- data/lib/redis/connection/ruby.rb +53 -48
- data/lib/redis/distributed.rb +6 -6
- data/lib/redis/version.rb +1 -1
- 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: 416a2f007042c19453c13361aa4440a507e47fb32c28adc68e7c574c6651f5b4
|
4
|
+
data.tar.gz: 1a845f2af649d64f8b274962c9d5d10e6eb5d046474b6e44288676432fe8a98b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3766992242ae284ca474bc8564c6760de88e635a8c3bc3c80da08062d698cc891bf00455b5d98768709ecc766f8ad305fe03cc5806f03fda3ebb93049e0a1cce
|
7
|
+
data.tar.gz: f440c984ec58ff091a6a696952239cb04cf145752b485543e5da7215a327b40be4391b3fe6ca67753f84ec43913b9d90ec0b6f812e1696890a7c17cbf3aa3630
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,28 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 4.3.1
|
4
|
+
|
5
|
+
* Fix password authentication against redis server 5 and older.
|
6
|
+
|
7
|
+
# 4.3.0
|
8
|
+
|
9
|
+
* Add the TYPE argument to scan and scan_each. See #985.
|
10
|
+
* Support AUTH command for ACL. See #967.
|
11
|
+
|
12
|
+
# 4.2.5
|
13
|
+
|
14
|
+
* Optimize the ruby connector write buffering. See #964.
|
15
|
+
|
16
|
+
# 4.2.4
|
17
|
+
|
18
|
+
* Fix bytesize calculations in the ruby connector, and work on a copy of the buffer. Fix #961, #962.
|
19
|
+
|
20
|
+
# 4.2.3
|
21
|
+
|
22
|
+
* Use io/wait instead of IO.select in the ruby connector. See #960.
|
23
|
+
* Use exception free non blocking IOs in the ruby connector. See #926.
|
24
|
+
* Prevent corruption of the client when an interrupt happen during inside a pipeline block. See #945.
|
25
|
+
|
3
26
|
# 4.2.2
|
4
27
|
|
5
28
|
* Fix `WATCH` support for `Redis::Distributed`. See #941.
|
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
|
@@ -265,6 +271,7 @@ All timeout values are specified in seconds.
|
|
265
271
|
When using pub/sub, you can subscribe to a channel using a timeout as well:
|
266
272
|
|
267
273
|
```ruby
|
274
|
+
redis = Redis.new(reconnect_attempts: 0)
|
268
275
|
redis.subscribe_with_timeout(5, "news") do |on|
|
269
276
|
on.message do |channel, message|
|
270
277
|
# ...
|
@@ -439,7 +446,7 @@ redis = Redis.new(:driver => :synchrony)
|
|
439
446
|
## Testing
|
440
447
|
|
441
448
|
This library is tested against recent Ruby and Redis versions.
|
442
|
-
Check [
|
449
|
+
Check [Github Actions][gh-actions-link] for the exact versions supported.
|
443
450
|
|
444
451
|
## See Also
|
445
452
|
|
@@ -458,12 +465,11 @@ client and evangelized Redis in Rubyland. Thank you, Ezra.
|
|
458
465
|
requests.
|
459
466
|
|
460
467
|
|
461
|
-
[inchpages-image]:
|
462
|
-
[inchpages-link]:
|
463
|
-
[redis-commands]:
|
464
|
-
[redis-home]:
|
465
|
-
[redis-url]:
|
466
|
-
[
|
467
|
-
[
|
468
|
-
[
|
469
|
-
[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.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
|
|
@@ -1170,23 +1172,29 @@ class Redis
|
|
1170
1172
|
end
|
1171
1173
|
end
|
1172
1174
|
|
1173
|
-
# Remove and get the first
|
1175
|
+
# Remove and get the first elements in a list.
|
1174
1176
|
#
|
1175
1177
|
# @param [String] key
|
1176
|
-
# @
|
1177
|
-
|
1178
|
+
# @param [Integer] count number of elements to remove
|
1179
|
+
# @return [String, Array<String>] the values of the first elements
|
1180
|
+
def lpop(key, count = nil)
|
1178
1181
|
synchronize do |client|
|
1179
|
-
|
1182
|
+
command = [:lpop, key]
|
1183
|
+
command << count if count
|
1184
|
+
client.call(command)
|
1180
1185
|
end
|
1181
1186
|
end
|
1182
1187
|
|
1183
|
-
# Remove and get the last
|
1188
|
+
# Remove and get the last elements in a list.
|
1184
1189
|
#
|
1185
1190
|
# @param [String] key
|
1186
|
-
# @
|
1187
|
-
|
1191
|
+
# @param [Integer] count number of elements to remove
|
1192
|
+
# @return [String, Array<String>] the values of the last elements
|
1193
|
+
def rpop(key, count = nil)
|
1188
1194
|
synchronize do |client|
|
1189
|
-
|
1195
|
+
command = [:rpop, key]
|
1196
|
+
command << count if count
|
1197
|
+
client.call(command)
|
1190
1198
|
end
|
1191
1199
|
end
|
1192
1200
|
|
@@ -2438,14 +2446,13 @@ class Redis
|
|
2438
2446
|
end
|
2439
2447
|
|
2440
2448
|
def pipelined
|
2441
|
-
synchronize do |
|
2449
|
+
synchronize do |prior_client|
|
2442
2450
|
begin
|
2443
|
-
|
2444
|
-
original, @client = @client, pipeline
|
2451
|
+
@client = Pipeline.new(prior_client)
|
2445
2452
|
yield(self)
|
2446
|
-
|
2453
|
+
prior_client.call_pipeline(@client)
|
2447
2454
|
ensure
|
2448
|
-
@client =
|
2455
|
+
@client = prior_client
|
2449
2456
|
end
|
2450
2457
|
end
|
2451
2458
|
end
|
@@ -2481,17 +2488,16 @@ class Redis
|
|
2481
2488
|
# @see #watch
|
2482
2489
|
# @see #unwatch
|
2483
2490
|
def multi
|
2484
|
-
synchronize do |
|
2491
|
+
synchronize do |prior_client|
|
2485
2492
|
if !block_given?
|
2486
|
-
|
2493
|
+
prior_client.call([:multi])
|
2487
2494
|
else
|
2488
2495
|
begin
|
2489
|
-
|
2490
|
-
original, @client = @client, pipeline
|
2496
|
+
@client = Pipeline::Multi.new(prior_client)
|
2491
2497
|
yield(self)
|
2492
|
-
|
2498
|
+
prior_client.call_pipeline(@client)
|
2493
2499
|
ensure
|
2494
|
-
@client =
|
2500
|
+
@client = prior_client
|
2495
2501
|
end
|
2496
2502
|
end
|
2497
2503
|
end
|
@@ -2638,12 +2644,13 @@ class Redis
|
|
2638
2644
|
_eval(:evalsha, args)
|
2639
2645
|
end
|
2640
2646
|
|
2641
|
-
def _scan(command, cursor, args, match: nil, count: nil, &block)
|
2647
|
+
def _scan(command, cursor, args, match: nil, count: nil, type: nil, &block)
|
2642
2648
|
# SSCAN/ZSCAN/HSCAN already prepend the key to +args+.
|
2643
2649
|
|
2644
2650
|
args << cursor
|
2645
2651
|
args << "MATCH" << match if match
|
2646
2652
|
args << "COUNT" << count if count
|
2653
|
+
args << "TYPE" << type if type
|
2647
2654
|
|
2648
2655
|
synchronize do |client|
|
2649
2656
|
client.call([command] + args, &block)
|
@@ -2658,11 +2665,15 @@ class Redis
|
|
2658
2665
|
# @example Retrieve a batch of keys matching a pattern
|
2659
2666
|
# redis.scan(4, :match => "key:1?")
|
2660
2667
|
# # => ["92", ["key:13", "key:18"]]
|
2668
|
+
# @example Retrieve a batch of keys of a certain type
|
2669
|
+
# redis.scan(92, :type => "zset")
|
2670
|
+
# # => ["173", ["sortedset:14", "sortedset:78"]]
|
2661
2671
|
#
|
2662
2672
|
# @param [String, Integer] cursor the cursor of the iteration
|
2663
2673
|
# @param [Hash] options
|
2664
2674
|
# - `:match => String`: only return keys matching the pattern
|
2665
2675
|
# - `:count => Integer`: return count keys at most per iteration
|
2676
|
+
# - `:type => String`: return keys only of the given type
|
2666
2677
|
#
|
2667
2678
|
# @return [String, Array<String>] the next cursor and all found keys
|
2668
2679
|
def scan(cursor, **options)
|
@@ -2678,10 +2689,15 @@ class Redis
|
|
2678
2689
|
# redis.scan_each(:match => "key:1?") {|key| puts key}
|
2679
2690
|
# # => key:13
|
2680
2691
|
# # => key:18
|
2692
|
+
# @example Execute block for each key of a type
|
2693
|
+
# redis.scan_each(:type => "hash") {|key| puts redis.type(key)}
|
2694
|
+
# # => "hash"
|
2695
|
+
# # => "hash"
|
2681
2696
|
#
|
2682
2697
|
# @param [Hash] options
|
2683
2698
|
# - `:match => String`: only return keys matching the pattern
|
2684
2699
|
# - `:count => Integer`: return count keys at most per iteration
|
2700
|
+
# - `:type => String`: return keys only of the given type
|
2685
2701
|
#
|
2686
2702
|
# @return [Enumerator] an enumerator for all found keys
|
2687
2703
|
def scan_each(**options, &block)
|
data/lib/redis/client.rb
CHANGED
@@ -6,13 +6,18 @@ require "cgi"
|
|
6
6
|
|
7
7
|
class Redis
|
8
8
|
class Client
|
9
|
+
# Defaults are also used for converting string keys to symbols.
|
9
10
|
DEFAULTS = {
|
10
11
|
url: -> { ENV["REDIS_URL"] },
|
11
12
|
scheme: "redis",
|
12
13
|
host: "127.0.0.1",
|
13
14
|
port: 6379,
|
14
15
|
path: nil,
|
16
|
+
read_timeout: nil,
|
17
|
+
write_timeout: nil,
|
18
|
+
connect_timeout: nil,
|
15
19
|
timeout: 5.0,
|
20
|
+
username: nil,
|
16
21
|
password: nil,
|
17
22
|
db: 0,
|
18
23
|
driver: nil,
|
@@ -22,6 +27,7 @@ class Redis
|
|
22
27
|
reconnect_delay: 0,
|
23
28
|
reconnect_delay_max: 0.5,
|
24
29
|
inherit_socket: false,
|
30
|
+
logger: nil,
|
25
31
|
sentinels: nil,
|
26
32
|
role: nil
|
27
33
|
}.freeze
|
@@ -56,6 +62,10 @@ class Redis
|
|
56
62
|
@options[:read_timeout]
|
57
63
|
end
|
58
64
|
|
65
|
+
def username
|
66
|
+
@options[:username]
|
67
|
+
end
|
68
|
+
|
59
69
|
def password
|
60
70
|
@options[:password]
|
61
71
|
end
|
@@ -105,7 +115,17 @@ class Redis
|
|
105
115
|
# Don't try to reconnect when the connection is fresh
|
106
116
|
with_reconnect(false) do
|
107
117
|
establish_connection
|
108
|
-
|
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
|
109
129
|
call [:select, db] if db != 0
|
110
130
|
call [:client, :setname, @options[:id]] if @options[:id]
|
111
131
|
@connector.check(self)
|
@@ -126,7 +146,7 @@ class Redis
|
|
126
146
|
reply = process([command]) { read }
|
127
147
|
raise reply if reply.is_a?(CommandError)
|
128
148
|
|
129
|
-
if block_given?
|
149
|
+
if block_given? && reply != 'QUEUED'
|
130
150
|
yield reply
|
131
151
|
else
|
132
152
|
reply
|
@@ -429,7 +449,8 @@ class Redis
|
|
429
449
|
defaults[:scheme] = uri.scheme
|
430
450
|
defaults[:host] = uri.host if uri.host
|
431
451
|
defaults[:port] = uri.port if uri.port
|
432
|
-
defaults[:
|
452
|
+
defaults[:username] = CGI.unescape(uri.user) if uri.user && !uri.user.empty?
|
453
|
+
defaults[:password] = CGI.unescape(uri.password) if uri.password && !uri.password.empty?
|
433
454
|
defaults[:db] = uri.path[1..-1].to_i if uri.path
|
434
455
|
defaults[:role] = :master
|
435
456
|
else
|
@@ -505,7 +526,7 @@ class Redis
|
|
505
526
|
require_relative "connection/#{driver}"
|
506
527
|
rescue LoadError, NameError
|
507
528
|
begin
|
508
|
-
require "connection/#{driver}"
|
529
|
+
require "redis/connection/#{driver}"
|
509
530
|
rescue LoadError, NameError => error
|
510
531
|
raise "Cannot load driver #{driver.inspect}: #{error.message}"
|
511
532
|
end
|
@@ -574,6 +595,7 @@ class Redis
|
|
574
595
|
client = Client.new(@options.merge({
|
575
596
|
host: sentinel[:host] || sentinel["host"],
|
576
597
|
port: sentinel[:port] || sentinel["port"],
|
598
|
+
username: sentinel[:username] || sentinel["username"],
|
577
599
|
password: sentinel[:password] || sentinel["password"],
|
578
600
|
reconnect_attempts: 0
|
579
601
|
}))
|
data/lib/redis/cluster.rb
CHANGED
@@ -128,7 +128,7 @@ class Redis
|
|
128
128
|
def send_command(command, &block)
|
129
129
|
cmd = command.first.to_s.downcase
|
130
130
|
case cmd
|
131
|
-
when 'auth', 'bgrewriteaof', 'bgsave', 'quit', 'save'
|
131
|
+
when 'acl', 'auth', 'bgrewriteaof', 'bgsave', 'quit', 'save'
|
132
132
|
@node.call_all(command, &block).first
|
133
133
|
when 'flushall', 'flushdb'
|
134
134
|
@node.call_master(command, &block).first
|
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
|
|
@@ -49,57 +49,50 @@ class Redis
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def _read_from_socket(nbytes)
|
52
|
-
|
53
|
-
read_nonblock(nbytes)
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
67
|
-
rescue EOFError
|
68
|
-
raise Errno::ECONNRESET
|
69
|
-
end
|
70
|
-
|
71
|
-
def _write_to_socket(data)
|
72
|
-
begin
|
73
|
-
write_nonblock(data)
|
74
|
-
rescue IO::WaitWritable
|
75
|
-
if IO.select(nil, [self], nil, @write_timeout)
|
76
|
-
retry
|
77
|
-
else
|
78
|
-
raise Redis::TimeoutError
|
79
|
-
end
|
80
|
-
rescue IO::WaitReadable
|
81
|
-
if IO.select([self], nil, nil, @write_timeout)
|
82
|
-
retry
|
83
|
-
else
|
84
|
-
raise Redis::TimeoutError
|
52
|
+
loop do
|
53
|
+
case chunk = read_nonblock(nbytes, exception: false)
|
54
|
+
when :wait_readable
|
55
|
+
unless wait_readable(@timeout)
|
56
|
+
raise Redis::TimeoutError
|
57
|
+
end
|
58
|
+
when :wait_writable
|
59
|
+
unless wait_writable(@timeout)
|
60
|
+
raise Redis::TimeoutError
|
61
|
+
end
|
62
|
+
when nil
|
63
|
+
raise Errno::ECONNRESET
|
64
|
+
when String
|
65
|
+
return chunk
|
85
66
|
end
|
86
67
|
end
|
87
|
-
rescue EOFError
|
88
|
-
raise Errno::ECONNRESET
|
89
68
|
end
|
90
69
|
|
91
|
-
def write(
|
92
|
-
return super(
|
70
|
+
def write(buffer)
|
71
|
+
return super(buffer) unless @write_timeout
|
93
72
|
|
94
|
-
|
95
|
-
|
73
|
+
bytes_to_write = buffer.bytesize
|
74
|
+
total_bytes_written = 0
|
96
75
|
loop do
|
97
|
-
|
76
|
+
case bytes_written = write_nonblock(buffer, exception: false)
|
77
|
+
when :wait_readable
|
78
|
+
unless wait_readable(@write_timeout)
|
79
|
+
raise Redis::TimeoutError
|
80
|
+
end
|
81
|
+
when :wait_writable
|
82
|
+
unless wait_writable(@write_timeout)
|
83
|
+
raise Redis::TimeoutError
|
84
|
+
end
|
85
|
+
when nil
|
86
|
+
raise Errno::ECONNRESET
|
87
|
+
when Integer
|
88
|
+
total_bytes_written += bytes_written
|
98
89
|
|
99
|
-
|
100
|
-
|
90
|
+
if total_bytes_written >= bytes_to_write
|
91
|
+
return total_bytes_written
|
92
|
+
end
|
101
93
|
|
102
|
-
|
94
|
+
buffer = buffer.byteslice(bytes_written..-1)
|
95
|
+
end
|
103
96
|
end
|
104
97
|
end
|
105
98
|
end
|
@@ -135,7 +128,7 @@ class Redis
|
|
135
128
|
raise TimeoutError
|
136
129
|
end
|
137
130
|
|
138
|
-
# JRuby raises Errno::EAGAIN on #read_nonblock even when
|
131
|
+
# JRuby raises Errno::EAGAIN on #read_nonblock even when it
|
139
132
|
# says it is readable (1.6.6, in both 1.8 and 1.9 mode).
|
140
133
|
# Use the blocking #readpartial method instead.
|
141
134
|
|
@@ -160,7 +153,7 @@ class Redis
|
|
160
153
|
begin
|
161
154
|
sock.connect_nonblock(sockaddr)
|
162
155
|
rescue Errno::EINPROGRESS
|
163
|
-
raise TimeoutError
|
156
|
+
raise TimeoutError unless sock.wait_writable(timeout)
|
164
157
|
|
165
158
|
begin
|
166
159
|
sock.connect_nonblock(sockaddr)
|
@@ -215,7 +208,7 @@ class Redis
|
|
215
208
|
begin
|
216
209
|
sock.connect_nonblock(sockaddr)
|
217
210
|
rescue Errno::EINPROGRESS
|
218
|
-
raise TimeoutError
|
211
|
+
raise TimeoutError unless sock.wait_writable(timeout)
|
219
212
|
|
220
213
|
begin
|
221
214
|
sock.connect_nonblock(sockaddr)
|
@@ -233,6 +226,18 @@ class Redis
|
|
233
226
|
class SSLSocket < ::OpenSSL::SSL::SSLSocket
|
234
227
|
include SocketMixin
|
235
228
|
|
229
|
+
unless method_defined?(:wait_readable)
|
230
|
+
def wait_readable(timeout = nil)
|
231
|
+
to_io.wait_readable(timeout)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
unless method_defined?(:wait_writable)
|
236
|
+
def wait_writable(timeout = nil)
|
237
|
+
to_io.wait_writable(timeout)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
236
241
|
def self.connect(host, port, timeout, ssl_params)
|
237
242
|
# Note: this is using Redis::Connection::TCPSocket
|
238
243
|
tcp_sock = TCPSocket.connect(host, port, timeout)
|
@@ -254,13 +259,13 @@ class Redis
|
|
254
259
|
# Instead, you have to retry.
|
255
260
|
ssl_sock.connect_nonblock
|
256
261
|
rescue Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable
|
257
|
-
if
|
262
|
+
if ssl_sock.wait_readable(timeout)
|
258
263
|
retry
|
259
264
|
else
|
260
265
|
raise TimeoutError
|
261
266
|
end
|
262
267
|
rescue IO::WaitWritable
|
263
|
-
if
|
268
|
+
if ssl_sock.wait_writable(timeout)
|
264
269
|
retry
|
265
270
|
else
|
266
271
|
raise TimeoutError
|
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
|
data/lib/redis/version.rb
CHANGED
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.3.1
|
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-06-11 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.3.1
|
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.3.1
|
108
108
|
post_install_message:
|
109
109
|
rdoc_options: []
|
110
110
|
require_paths:
|