redis 4.7.1 → 5.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +46 -0
- data/README.md +75 -161
- data/lib/redis/client.rb +92 -608
- 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/geo.rb +3 -3
- data/lib/redis/commands/hashes.rb +8 -5
- data/lib/redis/commands/hyper_log_log.rb +1 -1
- data/lib/redis/commands/keys.rb +53 -27
- data/lib/redis/commands/lists.rb +19 -23
- data/lib/redis/commands/pubsub.rb +7 -25
- data/lib/redis/commands/server.rb +15 -15
- data/lib/redis/commands/sets.rb +43 -36
- data/lib/redis/commands/sorted_sets.rb +18 -12
- data/lib/redis/commands/streams.rb +12 -10
- data/lib/redis/commands/strings.rb +16 -15
- data/lib/redis/commands/transactions.rb +7 -31
- data/lib/redis/commands.rb +1 -8
- data/lib/redis/distributed.rb +100 -67
- data/lib/redis/errors.rb +14 -50
- data/lib/redis/hash_ring.rb +26 -26
- data/lib/redis/pipeline.rb +43 -222
- data/lib/redis/subscribe.rb +23 -15
- data/lib/redis/version.rb +1 -1
- data/lib/redis.rb +88 -182
- metadata +9 -53
- 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: f65967c3d313cca4af20076de88097790ae39dd7935cd9ef25f6ce4d6200c0a5
|
4
|
+
data.tar.gz: f744db40e4de3794921aedd4d792eb7f275c24e4bd88e8954ce4b3b56a1b2d64
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1368bd997873d59bc5910ac1d1431a53ff2fde0179c4398e35c645d3a6b605695294ff959a79940a74d54b2fc3dd1dc75d6e70636d1cf611285c5c215e64aaa5
|
7
|
+
data.tar.gz: cb1b07ce5cb323b92ad50846165350ed740729f00df50cdb6a8162e961fbf5c9bda2bf83db2eff0413416e8800c8510698d46b5678f0fe74f45f0935fc1b1fff
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,51 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 5.0.4
|
4
|
+
|
5
|
+
- Cast `ttl` argument to integer in `expire`, `setex` and a few others.
|
6
|
+
|
7
|
+
# 5.0.3
|
8
|
+
|
9
|
+
- Add `OutOfMemoryError` as a subclass of `CommandError`
|
10
|
+
|
11
|
+
# 5.0.2
|
12
|
+
|
13
|
+
- Fix `Redis#close` to properly reset the fork protection check.
|
14
|
+
|
15
|
+
# 5.0.1
|
16
|
+
|
17
|
+
- Added a fake `Redis::Connections.drivers` method to be compatible with older sidekiq versions.
|
18
|
+
|
19
|
+
# 5.0.0
|
20
|
+
|
21
|
+
- Eagerly and strictly cast Integer and Float parameters.
|
22
|
+
- Allow to call `subscribe`, `unsubscribe`, `psubscribe` and `punsubscribe` from a subscribed client. See #1131.
|
23
|
+
- Use `MD5` for hashing server nodes in `Redis::Distributed`. This should improve keys distribution among servers. See #1089.
|
24
|
+
- Changed `sadd` and `srem` to now always return an Integer.
|
25
|
+
- Added `sadd?` and `srem?` which always return a Boolean.
|
26
|
+
- Added support for `IDLE` paramter in `xpending`.
|
27
|
+
- Cluster support has been moved to a `redis-clustering` companion gem.
|
28
|
+
- `select` no longer record the current database. If the client has to reconnect after `select` was used, it will reconnect to the original database.
|
29
|
+
- Better support Float timeout in blocking commands. See #977.
|
30
|
+
- Removed positional timeout in blocking commands (`BLPOP`, etc). Timeout now must be passed as an option: `r.blpop("key", timeout: 2.5)`
|
31
|
+
- Removed `logger` option.
|
32
|
+
- Removed `reconnect_delay_max` and `reconnect_delay`, you can pass precise sleep durations to `reconnect_attempts` instead.
|
33
|
+
- Require Ruby 2.5+.
|
34
|
+
- Removed the deprecated `queue` and `commit` methods. Use `pipelined` instead.
|
35
|
+
- Removed the deprecated `Redis::Future#==`.
|
36
|
+
- Removed the deprecated `pipelined` and `multi` signature. Commands now MUST be called on the block argument, not the original redis instance.
|
37
|
+
- Removed `Redis.current`. You shouldn't assume there is a single global Redis connection, use a connection pool instead,
|
38
|
+
and libaries using Redis should accept a Redis instance (or connection pool) as a config. E.g. `MyLibrary.redis = Redis.new(...)`.
|
39
|
+
- Removed the `synchrony` driver.
|
40
|
+
- Removed `Redis.exists_returns_integer`, it's now always enabled.
|
41
|
+
|
42
|
+
# 4.8.0
|
43
|
+
|
44
|
+
* Introduce `sadd?` and `srem?` as boolean returning versions of `sadd` and `srem`.
|
45
|
+
* Deprecate `sadd` and `srem` returning a boolean when called with a single argument.
|
46
|
+
To enable the redis 5.0 behavior you can set `Redis.sadd_returns_boolean = false`.
|
47
|
+
* Deprecate passing `timeout` as a positional argument in blocking commands (`brpop`, `blop`, etc).
|
48
|
+
|
3
49
|
# 4.7.1
|
4
50
|
|
5
51
|
* 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,26 @@ 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](https://github.com/mperham/connection_pool), e.g.:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
module MyApp
|
84
|
+
def self.redis
|
85
|
+
@redis ||= ConnectionPool::Wrapper.new do
|
86
|
+
Redis.new(url: ENV["REDIS_URL"])
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
MyApp.redis.incr("some-counter")
|
92
|
+
```
|
93
|
+
|
79
94
|
## Sentinel support
|
80
95
|
|
81
96
|
The client is able to perform automatic failover by using [Redis
|
@@ -111,79 +126,12 @@ If you want to [authenticate](https://redis.io/topics/sentinel#configuring-senti
|
|
111
126
|
SENTINELS = [{ host: '127.0.0.1', port: 26380, password: 'mysecret' },
|
112
127
|
{ host: '127.0.0.1', port: 26381, password: 'mysecret' }]
|
113
128
|
|
114
|
-
redis = Redis.new(
|
129
|
+
redis = Redis.new(name: 'mymaster', sentinels: SENTINELS, role: :master)
|
115
130
|
```
|
116
131
|
|
117
132
|
## Cluster support
|
118
133
|
|
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
|
-
```
|
134
|
+
[Clustering](https://redis.io/topics/cluster-spec). is supported via the [`redis-clustering` gem](cluster/).
|
187
135
|
|
188
136
|
## Pipelining
|
189
137
|
|
@@ -206,6 +154,17 @@ end
|
|
206
154
|
# => ["OK", 1]
|
207
155
|
```
|
208
156
|
|
157
|
+
Commands must be called on the yielded objects. If you call methods
|
158
|
+
on the original client objects from inside a pipeline, they will be sent immediately:
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
redis.pipelined do |pipeline|
|
162
|
+
pipeline.set "foo", "bar"
|
163
|
+
redis.incr "baz" # => 1
|
164
|
+
end
|
165
|
+
# => ["OK"]
|
166
|
+
```
|
167
|
+
|
209
168
|
### Executing commands atomically
|
210
169
|
|
211
170
|
You can use `MULTI/EXEC` to run a number of commands in an atomic
|
@@ -225,21 +184,22 @@ end
|
|
225
184
|
### Futures
|
226
185
|
|
227
186
|
Replies to commands in a pipeline can be accessed via the *futures* they
|
228
|
-
emit
|
187
|
+
emit. All calls on the pipeline object return a
|
229
188
|
`Future` object, which responds to the `#value` method. When the
|
230
189
|
pipeline has successfully executed, all futures are assigned their
|
231
190
|
respective replies and can be used.
|
232
191
|
|
233
192
|
```ruby
|
193
|
+
set = incr = nil
|
234
194
|
redis.pipelined do |pipeline|
|
235
|
-
|
236
|
-
|
195
|
+
set = pipeline.set "foo", "bar"
|
196
|
+
incr = pipeline.incr "baz"
|
237
197
|
end
|
238
198
|
|
239
|
-
|
199
|
+
set.value
|
240
200
|
# => "OK"
|
241
201
|
|
242
|
-
|
202
|
+
incr.value
|
243
203
|
# => 1
|
244
204
|
```
|
245
205
|
|
@@ -251,7 +211,7 @@ it can't connect to the server a `Redis::CannotConnectError` error will be raise
|
|
251
211
|
```ruby
|
252
212
|
begin
|
253
213
|
redis.ping
|
254
|
-
rescue
|
214
|
+
rescue Redis::BaseError => e
|
255
215
|
e.inspect
|
256
216
|
# => #<Redis::CannotConnectError: Timed out connecting to Redis on 10.0.1.1:6380>
|
257
217
|
|
@@ -298,55 +258,37 @@ If no message is received after 5 seconds, the client will unsubscribe.
|
|
298
258
|
|
299
259
|
## Reconnections
|
300
260
|
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
`reconnect_delay` and `reconnect_delay_max`.
|
261
|
+
**By default**, this gem will only **retry a connection once** and then fail, but
|
262
|
+
the client allows you to configure how many `reconnect_attempts` it should
|
263
|
+
complete before declaring a connection as failed.
|
305
264
|
|
306
265
|
```ruby
|
307
|
-
Redis.new(
|
308
|
-
|
309
|
-
:reconnect_delay => 1.5,
|
310
|
-
:reconnect_delay_max => 10.0,
|
311
|
-
)
|
266
|
+
Redis.new(reconnect_attempts: 0)
|
267
|
+
Redis.new(reconnect_attempts: 3)
|
312
268
|
```
|
313
269
|
|
314
|
-
|
315
|
-
|
316
|
-
between each attempt but it never waits longer than `reconnect_delay_max`.
|
317
|
-
|
318
|
-
This is the retry algorithm:
|
270
|
+
If you wish to wait between reconnection attempts, you can instead pass a list
|
271
|
+
of durations:
|
319
272
|
|
320
273
|
```ruby
|
321
|
-
|
274
|
+
Redis.new(reconnect_attempts: [
|
275
|
+
0, # retry immediately
|
276
|
+
0.25 # retry a second time after 250ms
|
277
|
+
1 # retry a third and final time after another 1s
|
278
|
+
])
|
322
279
|
```
|
323
280
|
|
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`.
|
281
|
+
If you wish to disable reconnection only for some commands, you can use
|
282
|
+
`disable_reconnection`:
|
344
283
|
|
345
|
-
|
284
|
+
```ruby
|
285
|
+
redis.get("some-key") # this may be retried
|
286
|
+
redis.disable_reconnection do
|
287
|
+
redis.incr("some-counter") # this won't be retried.
|
288
|
+
end
|
289
|
+
```
|
346
290
|
|
347
|
-
|
348
|
-
when talking to Redis via a server-side proxy such as [stunnel], [hitch],
|
349
|
-
or [ghostunnel].
|
291
|
+
## SSL/TLS Support
|
350
292
|
|
351
293
|
To enable SSL support, pass the `:ssl => true` option when configuring the
|
352
294
|
Redis client, or pass in `:url => "rediss://..."` (like HTTPS for Redis).
|
@@ -381,13 +323,7 @@ redis = Redis.new(
|
|
381
323
|
)
|
382
324
|
```
|
383
325
|
|
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
|
-
|
326
|
+
[OpenSSL::SSL::SSLContext documentation]: http://ruby-doc.org/stdlib-2.5.0/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html
|
391
327
|
|
392
328
|
## Expert-Mode Options
|
393
329
|
|
@@ -401,17 +337,9 @@ redis = Redis.new(
|
|
401
337
|
Improper use of `inherit_socket` will result in corrupted and/or incorrect
|
402
338
|
responses.
|
403
339
|
|
404
|
-
##
|
340
|
+
## hiredis binding
|
405
341
|
|
406
342
|
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
343
|
|
416
344
|
The hiredis driver uses the connection facility of hiredis-rb. In turn,
|
417
345
|
hiredis-rb is a binding to the official hiredis client library. It
|
@@ -421,41 +349,27 @@ extension, JRuby is not supported (by default).
|
|
421
349
|
It is best to use hiredis when you have large replies (for example:
|
422
350
|
`LRANGE`, `SMEMBERS`, `ZRANGE`, etc.) and/or use big pipelines.
|
423
351
|
|
424
|
-
In your Gemfile, include hiredis
|
352
|
+
In your Gemfile, include `hiredis-client`:
|
425
353
|
|
426
354
|
```ruby
|
427
|
-
gem "redis"
|
428
|
-
gem "hiredis"
|
355
|
+
gem "redis"
|
356
|
+
gem "hiredis-client"
|
429
357
|
```
|
430
358
|
|
431
|
-
|
359
|
+
If your application doesn't call `Bundler.require`, you may have
|
360
|
+
to require it explictly:
|
432
361
|
|
433
362
|
```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.
|
363
|
+
require "hiredis-client"
|
364
|
+
````
|
444
365
|
|
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
|
-
```
|
366
|
+
This makes the hiredis driver the default.
|
454
367
|
|
455
|
-
|
368
|
+
If you want to be certain hiredis is being used, when instantiating
|
369
|
+
the client object, specify hiredis:
|
456
370
|
|
457
371
|
```ruby
|
458
|
-
redis = Redis.new(:
|
372
|
+
redis = Redis.new(driver: :hiredis)
|
459
373
|
```
|
460
374
|
|
461
375
|
## Testing
|