redis 4.7.1 → 5.0.0.beta3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/README.md +77 -161
- data/lib/redis/client.rb +78 -615
- data/lib/redis/commands/bitmaps.rb +4 -1
- data/lib/redis/commands/cluster.rb +1 -18
- data/lib/redis/commands/connection.rb +5 -10
- data/lib/redis/commands/hashes.rb +6 -3
- data/lib/redis/commands/hyper_log_log.rb +1 -1
- data/lib/redis/commands/keys.rb +52 -26
- data/lib/redis/commands/lists.rb +10 -14
- data/lib/redis/commands/pubsub.rb +7 -9
- data/lib/redis/commands/server.rb +14 -14
- data/lib/redis/commands/sets.rb +42 -35
- data/lib/redis/commands/sorted_sets.rb +4 -2
- data/lib/redis/commands/streams.rb +12 -10
- data/lib/redis/commands/strings.rb +1 -0
- data/lib/redis/commands/transactions.rb +7 -31
- data/lib/redis/commands.rb +1 -8
- data/lib/redis/distributed.rb +99 -66
- data/lib/redis/errors.rb +10 -52
- data/lib/redis/hash_ring.rb +26 -26
- data/lib/redis/pipeline.rb +43 -222
- data/lib/redis/subscribe.rb +15 -9
- data/lib/redis/version.rb +1 -1
- data/lib/redis.rb +67 -179
- metadata +13 -57
- data/lib/redis/cluster/command.rb +0 -79
- data/lib/redis/cluster/command_loader.rb +0 -33
- data/lib/redis/cluster/key_slot_converter.rb +0 -72
- data/lib/redis/cluster/node.rb +0 -120
- data/lib/redis/cluster/node_key.rb +0 -31
- data/lib/redis/cluster/node_loader.rb +0 -34
- data/lib/redis/cluster/option.rb +0 -100
- data/lib/redis/cluster/slot.rb +0 -86
- data/lib/redis/cluster/slot_loader.rb +0 -46
- data/lib/redis/cluster.rb +0 -315
- data/lib/redis/connection/command_helper.rb +0 -41
- data/lib/redis/connection/hiredis.rb +0 -66
- data/lib/redis/connection/registry.rb +0 -13
- data/lib/redis/connection/ruby.rb +0 -437
- data/lib/redis/connection/synchrony.rb +0 -148
- data/lib/redis/connection.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a8bcabf5f725061ad3fba18ed42eed7ce26788cf41b78f2091e6033530e124e0
|
4
|
+
data.tar.gz: 6b22ffde2abc13f944641c17972013cb4084dd91989127d6a3f9232b1b21ec5d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 21141ffa7c06d44599ba93097ec2000abd6325afe2e7175a15f0c0dddfae7b2a120b8acd5f14937f1c58fb971e2fd04603721388a53f6ea42b66031f8b1f9058
|
7
|
+
data.tar.gz: 1b0996205f973aba8c7db27726eacbe2a03e4339d0444eee80e68958a5226b70349437a518a5f8d0a7b419106e9c9ae546d349dbf7c639ca9a51a721ca96a51c
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 5.0.0.beta3
|
4
|
+
|
5
|
+
- Use `MD5` for hashing server nodes in `Redis::Distributed`. This should improve keys distribution among servers. See #1089.
|
6
|
+
- Changed `sadd` and `srem` to now always return an Integer.
|
7
|
+
- Added `sadd?` and `srem?` which always return a Boolean.
|
8
|
+
- Added support for `IDLE` paramter in `xpending`.
|
9
|
+
- Cluster support has been moved to a `rediscluster` companion gem.
|
10
|
+
- `select` no longer record the current database. If the client has to reconnect after `select` was used, it will reconnect to the original database.
|
11
|
+
- Better support Float timeout in blocking commands. See #977.
|
12
|
+
- Removed positional timeout in blocking commands (`BLPOP`, etc). Timeout now must be passed as an option: `r.blpop("key", timeout: 2.5)`
|
13
|
+
- Removed `logger` option.
|
14
|
+
- Removed `reconnect_delay_max` and `reconnect_delay`, you can pass precise sleep durations to `reconnect_attempts` instead.
|
15
|
+
- Require Ruby 2.5+.
|
16
|
+
- Removed the deprecated `queue` and `commit` methods. Use `pipelined` instead.
|
17
|
+
- Removed the deprecated `Redis::Future#==`.
|
18
|
+
- Removed the deprecated `pipelined` and `multi` signature. Commands now MUST be called on the block argument, not the original redis instance.
|
19
|
+
- Removed `Redis.current`. You shouldn't assume there is a single global Redis connection, use a connection pool instead,
|
20
|
+
and libaries using Redis should accept a Redis instance (or connection pool) as a config. E.g. `MyLibrary.redis = Redis.new(...)`.
|
21
|
+
- Removed the `synchrony` driver.
|
22
|
+
- Removed `Redis.exists_returns_integer`, it's now always enabled.
|
23
|
+
|
3
24
|
# 4.7.1
|
4
25
|
|
5
26
|
* Gracefully handle OpenSSL 3.0 EOF Errors (`OpenSSL::SSL::SSLError: SSL_read: unexpected eof while reading`). See #1106
|
data/README.md
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# redis-rb [![Build Status][gh-actions-image]][gh-actions-link] [![Inline docs][inchpages-image]][inchpages-link]
|
2
2
|
|
3
|
-
A Ruby client that tries to match [Redis][redis-home]' API one-to-one, while still
|
4
|
-
providing an idiomatic interface.
|
3
|
+
A Ruby client that tries to match [Redis][redis-home]' API one-to-one, while still providing an idiomatic interface.
|
5
4
|
|
6
5
|
See [RubyDoc.info][rubydoc] for the API docs of the latest published gem.
|
7
6
|
|
@@ -38,10 +37,6 @@ redis = Redis.new(url: "redis://:p4ssw0rd@10.0.1.1:6380/15")
|
|
38
37
|
The client expects passwords with special chracters to be URL-encoded (i.e.
|
39
38
|
`CGI.escape(password)`).
|
40
39
|
|
41
|
-
By default, the client will try to read the `REDIS_URL` environment variable
|
42
|
-
and use that as URL to connect to. The above statement is therefore equivalent
|
43
|
-
to setting this environment variable and calling `Redis.new` without arguments.
|
44
|
-
|
45
40
|
To connect to Redis listening on a Unix socket, try:
|
46
41
|
|
47
42
|
```ruby
|
@@ -76,6 +71,28 @@ redis.get("mykey")
|
|
76
71
|
All commands, their arguments, and return values are documented and
|
77
72
|
available on [RubyDoc.info][rubydoc].
|
78
73
|
|
74
|
+
## Connection Pooling and Thread safety
|
75
|
+
|
76
|
+
The client does not provide connection pooling. Each `Redis` instance
|
77
|
+
has one and only one connection to the server, and use of this connection
|
78
|
+
is protected by a mutex.
|
79
|
+
|
80
|
+
As such it is heavilly recommended to use the [`connection_pool` gem], e.g.:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
module MyApp
|
84
|
+
def self.redis
|
85
|
+
@redis ||= ConnectionPool.new do
|
86
|
+
Redis.new(url: ENV["REDIS_URL"])
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
MyApp.redis.incr("some-counter")
|
92
|
+
```
|
93
|
+
|
94
|
+
[`connection_pool` gem](https://github.com/mperham/connection_pool)
|
95
|
+
|
79
96
|
## Sentinel support
|
80
97
|
|
81
98
|
The client is able to perform automatic failover by using [Redis
|
@@ -111,79 +128,12 @@ If you want to [authenticate](https://redis.io/topics/sentinel#configuring-senti
|
|
111
128
|
SENTINELS = [{ host: '127.0.0.1', port: 26380, password: 'mysecret' },
|
112
129
|
{ host: '127.0.0.1', port: 26381, password: 'mysecret' }]
|
113
130
|
|
114
|
-
redis = Redis.new(
|
131
|
+
redis = Redis.new(name: 'mymaster', sentinels: SENTINELS, role: :master)
|
115
132
|
```
|
116
133
|
|
117
134
|
## Cluster support
|
118
135
|
|
119
|
-
|
120
|
-
|
121
|
-
```ruby
|
122
|
-
# Nodes can be passed to the client as an array of connection URLs.
|
123
|
-
nodes = (7000..7005).map { |port| "redis://127.0.0.1:#{port}" }
|
124
|
-
redis = Redis.new(cluster: nodes)
|
125
|
-
|
126
|
-
# You can also specify the options as a Hash. The options are the same as for a single server connection.
|
127
|
-
(7000..7005).map { |port| { host: '127.0.0.1', port: port } }
|
128
|
-
```
|
129
|
-
|
130
|
-
You can also specify only a subset of the nodes, and the client will discover the missing ones using the [CLUSTER NODES](https://redis.io/commands/cluster-nodes) command.
|
131
|
-
|
132
|
-
```ruby
|
133
|
-
Redis.new(cluster: %w[redis://127.0.0.1:7000])
|
134
|
-
```
|
135
|
-
|
136
|
-
If you want [the connection to be able to read from any replica](https://redis.io/commands/readonly), you must pass the `replica: true`. Note that this connection won't be usable to write keys.
|
137
|
-
|
138
|
-
```ruby
|
139
|
-
Redis.new(cluster: nodes, replica: true)
|
140
|
-
```
|
141
|
-
|
142
|
-
The calling code is responsible for [avoiding cross slot commands](https://redis.io/topics/cluster-spec#keys-distribution-model).
|
143
|
-
|
144
|
-
```ruby
|
145
|
-
redis = Redis.new(cluster: %w[redis://127.0.0.1:7000])
|
146
|
-
|
147
|
-
redis.mget('key1', 'key2')
|
148
|
-
#=> Redis::CommandError (CROSSSLOT Keys in request don't hash to the same slot)
|
149
|
-
|
150
|
-
redis.mget('{key}1', '{key}2')
|
151
|
-
#=> [nil, nil]
|
152
|
-
```
|
153
|
-
|
154
|
-
* The client automatically reconnects after a failover occurred, but the caller is responsible for handling errors while it is happening.
|
155
|
-
* The client support permanent node failures, and will reroute requests to promoted slaves.
|
156
|
-
* The client supports `MOVED` and `ASK` redirections transparently.
|
157
|
-
|
158
|
-
## Cluster mode with SSL/TLS
|
159
|
-
Since Redis can return FQDN of nodes in reply to client since `7.*` with CLUSTER commands, we can use cluster feature with SSL/TLS connection like this:
|
160
|
-
|
161
|
-
```ruby
|
162
|
-
Redis.new(cluster: %w[rediss://foo.example.com:6379])
|
163
|
-
```
|
164
|
-
|
165
|
-
On the other hand, in Redis versions prior to `6.*`, you can specify options like the following if cluster mode is enabled and client has to connect to nodes via single endpoint with SSL/TLS.
|
166
|
-
|
167
|
-
```ruby
|
168
|
-
Redis.new(cluster: %w[rediss://foo-endpoint.example.com:6379], fixed_hostname: 'foo-endpoint.example.com')
|
169
|
-
```
|
170
|
-
|
171
|
-
In case of the above architecture, if you don't pass the `fixed_hostname` option to the client and servers return IP addresses of nodes, the client may fail to verify certificates.
|
172
|
-
|
173
|
-
## Storing objects
|
174
|
-
|
175
|
-
Redis "string" types can be used to store serialized Ruby objects, for
|
176
|
-
example with JSON:
|
177
|
-
|
178
|
-
```ruby
|
179
|
-
require "json"
|
180
|
-
|
181
|
-
redis.set "foo", [1, 2, 3].to_json
|
182
|
-
# => OK
|
183
|
-
|
184
|
-
JSON.parse(redis.get("foo"))
|
185
|
-
# => [1, 2, 3]
|
186
|
-
```
|
136
|
+
[Clustering](https://redis.io/topics/cluster-spec). is supported via the [`redis-clustering` gem](cluster/).
|
187
137
|
|
188
138
|
## Pipelining
|
189
139
|
|
@@ -206,6 +156,17 @@ end
|
|
206
156
|
# => ["OK", 1]
|
207
157
|
```
|
208
158
|
|
159
|
+
Commands must be called on the yielded objects. If you call methods
|
160
|
+
on the original client objects from inside a pipeline, they willb e sent immediately:
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
redis.pipelined do |pipeline|
|
164
|
+
pipeline.set "foo", "bar"
|
165
|
+
redis.incr "baz" # => 1
|
166
|
+
end
|
167
|
+
# => ["OK"]
|
168
|
+
```
|
169
|
+
|
209
170
|
### Executing commands atomically
|
210
171
|
|
211
172
|
You can use `MULTI/EXEC` to run a number of commands in an atomic
|
@@ -225,21 +186,22 @@ end
|
|
225
186
|
### Futures
|
226
187
|
|
227
188
|
Replies to commands in a pipeline can be accessed via the *futures* they
|
228
|
-
emit
|
189
|
+
emit. All calls on the pipeline object return a
|
229
190
|
`Future` object, which responds to the `#value` method. When the
|
230
191
|
pipeline has successfully executed, all futures are assigned their
|
231
192
|
respective replies and can be used.
|
232
193
|
|
233
194
|
```ruby
|
195
|
+
set = incr = nil
|
234
196
|
redis.pipelined do |pipeline|
|
235
|
-
|
236
|
-
|
197
|
+
set = pipeline.set "foo", "bar"
|
198
|
+
incr = pipeline.incr "baz"
|
237
199
|
end
|
238
200
|
|
239
|
-
|
201
|
+
set.value
|
240
202
|
# => "OK"
|
241
203
|
|
242
|
-
|
204
|
+
incr.value
|
243
205
|
# => 1
|
244
206
|
```
|
245
207
|
|
@@ -251,7 +213,7 @@ it can't connect to the server a `Redis::CannotConnectError` error will be raise
|
|
251
213
|
```ruby
|
252
214
|
begin
|
253
215
|
redis.ping
|
254
|
-
rescue
|
216
|
+
rescue Redis::BaseError => e
|
255
217
|
e.inspect
|
256
218
|
# => #<Redis::CannotConnectError: Timed out connecting to Redis on 10.0.1.1:6380>
|
257
219
|
|
@@ -298,55 +260,37 @@ If no message is received after 5 seconds, the client will unsubscribe.
|
|
298
260
|
|
299
261
|
## Reconnections
|
300
262
|
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
`reconnect_delay` and `reconnect_delay_max`.
|
263
|
+
**By default**, this gem will only **retry a connection once** and then fail, but
|
264
|
+
the client allows you to configure how many `reconnect_attempts` it should
|
265
|
+
complete before declaring a connection as failed.
|
305
266
|
|
306
267
|
```ruby
|
307
|
-
Redis.new(
|
308
|
-
|
309
|
-
:reconnect_delay => 1.5,
|
310
|
-
:reconnect_delay_max => 10.0,
|
311
|
-
)
|
268
|
+
Redis.new(reconnect_attempts: 0)
|
269
|
+
Redis.new(reconnect_attempts: 3)
|
312
270
|
```
|
313
271
|
|
314
|
-
|
315
|
-
|
316
|
-
between each attempt but it never waits longer than `reconnect_delay_max`.
|
317
|
-
|
318
|
-
This is the retry algorithm:
|
272
|
+
If you wish to wait between reconnection attempts, you can instead pass a list
|
273
|
+
of durations:
|
319
274
|
|
320
275
|
```ruby
|
321
|
-
|
276
|
+
Redis.new(reconnect_attempts: [
|
277
|
+
0, # retry immediately
|
278
|
+
0.25 # retry a second time after 250ms
|
279
|
+
1 # retry a third and final time after another 1s
|
280
|
+
])
|
322
281
|
```
|
323
282
|
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
#|Attempt wait time|Total wait time
|
328
|
-
:-:|:-:|:-:
|
329
|
-
1|1.5s|1.5s
|
330
|
-
2|3.0s|4.5s
|
331
|
-
3|6.0s|10.5s
|
332
|
-
4|10.0s|20.5s
|
333
|
-
5|10.0s|30.5s
|
334
|
-
6|10.0s|40.5s
|
335
|
-
7|10.0s|50.5s
|
336
|
-
8|10.0s|60.5s
|
337
|
-
9|10.0s|70.5s
|
338
|
-
10|10.0s|80.5s
|
339
|
-
|
340
|
-
So if the reconnection attempt #10 succeeds 70 seconds have elapsed trying
|
341
|
-
to reconnect, this is likely fine in long-running background processes, but if
|
342
|
-
you use Redis to drive your website you might want to have a lower
|
343
|
-
`reconnect_delay_max` or have less `reconnect_attempts`.
|
283
|
+
If you wish to disable reconnection only for some commands, you can use
|
284
|
+
`disable_reconnection`:
|
344
285
|
|
345
|
-
|
286
|
+
```ruby
|
287
|
+
redis.get("some-key") # this may be retried
|
288
|
+
redis.disable_reconnection do
|
289
|
+
redis.incr("some-counter") # this won't be retried.
|
290
|
+
end
|
291
|
+
```
|
346
292
|
|
347
|
-
|
348
|
-
when talking to Redis via a server-side proxy such as [stunnel], [hitch],
|
349
|
-
or [ghostunnel].
|
293
|
+
## SSL/TLS Support
|
350
294
|
|
351
295
|
To enable SSL support, pass the `:ssl => true` option when configuring the
|
352
296
|
Redis client, or pass in `:url => "rediss://..."` (like HTTPS for Redis).
|
@@ -381,13 +325,7 @@ redis = Redis.new(
|
|
381
325
|
)
|
382
326
|
```
|
383
327
|
|
384
|
-
[
|
385
|
-
[hitch]: https://hitch-tls.org/
|
386
|
-
[ghostunnel]: https://github.com/square/ghostunnel
|
387
|
-
[OpenSSL::SSL::SSLContext documentation]: http://ruby-doc.org/stdlib-2.3.0/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html
|
388
|
-
|
389
|
-
*NOTE:* SSL is only supported by the default "Ruby" driver
|
390
|
-
|
328
|
+
[OpenSSL::SSL::SSLContext documentation]: http://ruby-doc.org/stdlib-2.5.0/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html
|
391
329
|
|
392
330
|
## Expert-Mode Options
|
393
331
|
|
@@ -401,17 +339,9 @@ redis = Redis.new(
|
|
401
339
|
Improper use of `inherit_socket` will result in corrupted and/or incorrect
|
402
340
|
responses.
|
403
341
|
|
404
|
-
##
|
342
|
+
## hiredis binding
|
405
343
|
|
406
344
|
By default, redis-rb uses Ruby's socket library to talk with Redis.
|
407
|
-
To use an alternative connection driver it should be specified as option
|
408
|
-
when instantiating the client object. These instructions are only valid
|
409
|
-
for **redis-rb 3.0**. For instructions on how to use alternate drivers from
|
410
|
-
**redis-rb 2.2**, please refer to an [older README][readme-2.2.2].
|
411
|
-
|
412
|
-
[readme-2.2.2]: https://github.com/redis/redis-rb/blob/v2.2.2/README.md
|
413
|
-
|
414
|
-
### hiredis
|
415
345
|
|
416
346
|
The hiredis driver uses the connection facility of hiredis-rb. In turn,
|
417
347
|
hiredis-rb is a binding to the official hiredis client library. It
|
@@ -421,41 +351,27 @@ extension, JRuby is not supported (by default).
|
|
421
351
|
It is best to use hiredis when you have large replies (for example:
|
422
352
|
`LRANGE`, `SMEMBERS`, `ZRANGE`, etc.) and/or use big pipelines.
|
423
353
|
|
424
|
-
In your Gemfile, include hiredis
|
354
|
+
In your Gemfile, include `hiredis-client`:
|
425
355
|
|
426
356
|
```ruby
|
427
|
-
gem "redis"
|
428
|
-
gem "hiredis"
|
357
|
+
gem "redis"
|
358
|
+
gem "hiredis-client"
|
429
359
|
```
|
430
360
|
|
431
|
-
|
361
|
+
If your application doesn't call `Bundler.require`, you may have
|
362
|
+
to require it explictly:
|
432
363
|
|
433
364
|
```ruby
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
### synchrony
|
438
|
-
|
439
|
-
The synchrony driver adds support for [em-synchrony][em-synchrony].
|
440
|
-
This makes redis-rb work with EventMachine's asynchronous I/O, while not
|
441
|
-
changing the exposed API. The hiredis gem needs to be available as
|
442
|
-
well, because the synchrony driver uses hiredis for parsing the Redis
|
443
|
-
protocol.
|
365
|
+
require "hiredis-client"
|
366
|
+
````
|
444
367
|
|
445
|
-
|
446
|
-
|
447
|
-
In your Gemfile, include em-synchrony and hiredis:
|
448
|
-
|
449
|
-
```ruby
|
450
|
-
gem "redis", "~> 3.0.1"
|
451
|
-
gem "hiredis", "~> 0.4.5"
|
452
|
-
gem "em-synchrony"
|
453
|
-
```
|
368
|
+
This makes the hiredis driver the default.
|
454
369
|
|
455
|
-
|
370
|
+
If you want to be certain hiredis is being used, when instantiating
|
371
|
+
the client object, specify hiredis:
|
456
372
|
|
457
373
|
```ruby
|
458
|
-
redis = Redis.new(:
|
374
|
+
redis = Redis.new(driver: :hiredis)
|
459
375
|
```
|
460
376
|
|
461
377
|
## Testing
|