redis 4.8.1 → 5.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +47 -2
  3. data/README.md +75 -161
  4. data/lib/redis/client.rb +77 -607
  5. data/lib/redis/commands/bitmaps.rb +4 -1
  6. data/lib/redis/commands/cluster.rb +1 -18
  7. data/lib/redis/commands/connection.rb +5 -10
  8. data/lib/redis/commands/geo.rb +3 -3
  9. data/lib/redis/commands/hashes.rb +9 -6
  10. data/lib/redis/commands/hyper_log_log.rb +1 -1
  11. data/lib/redis/commands/keys.rb +5 -23
  12. data/lib/redis/commands/lists.rb +20 -25
  13. data/lib/redis/commands/pubsub.rb +7 -25
  14. data/lib/redis/commands/server.rb +15 -15
  15. data/lib/redis/commands/sets.rb +31 -40
  16. data/lib/redis/commands/sorted_sets.rb +18 -12
  17. data/lib/redis/commands/streams.rb +39 -19
  18. data/lib/redis/commands/strings.rb +18 -17
  19. data/lib/redis/commands/transactions.rb +7 -31
  20. data/lib/redis/commands.rb +4 -7
  21. data/lib/redis/distributed.rb +86 -64
  22. data/lib/redis/errors.rb +15 -50
  23. data/lib/redis/hash_ring.rb +26 -26
  24. data/lib/redis/pipeline.rb +43 -222
  25. data/lib/redis/subscribe.rb +23 -15
  26. data/lib/redis/version.rb +1 -1
  27. data/lib/redis.rb +89 -184
  28. metadata +9 -53
  29. data/lib/redis/cluster/command.rb +0 -79
  30. data/lib/redis/cluster/command_loader.rb +0 -33
  31. data/lib/redis/cluster/key_slot_converter.rb +0 -72
  32. data/lib/redis/cluster/node.rb +0 -120
  33. data/lib/redis/cluster/node_key.rb +0 -31
  34. data/lib/redis/cluster/node_loader.rb +0 -34
  35. data/lib/redis/cluster/option.rb +0 -100
  36. data/lib/redis/cluster/slot.rb +0 -86
  37. data/lib/redis/cluster/slot_loader.rb +0 -46
  38. data/lib/redis/cluster.rb +0 -315
  39. data/lib/redis/connection/command_helper.rb +0 -41
  40. data/lib/redis/connection/hiredis.rb +0 -68
  41. data/lib/redis/connection/registry.rb +0 -13
  42. data/lib/redis/connection/ruby.rb +0 -437
  43. data/lib/redis/connection/synchrony.rb +0 -148
  44. data/lib/redis/connection.rb +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b18788ff80698e8f79fb103e7419d9ba74fb0b6a5eb55c672422cd76abff985c
4
- data.tar.gz: 1eed18a57039c677c894564ceaa1cf6bc9c0535be51501d078b09d75617a9d89
3
+ metadata.gz: 7b000349da8b2f7ae8ed14909175306d2c719a9873bf1dabe05c4719ae96d0da
4
+ data.tar.gz: fdcda2f50f9d33265f7ba24d3f29a2e078fabe5240e1eaf01efae51e0b83eb0b
5
5
  SHA512:
6
- metadata.gz: 5f2f7ce595d431f548c126a63c5ce697cc9e596e9b0eaa00f1e0186ae3853e73922c6e130b989ba9e026aec32f766a774433fdd1cff216420e837837db90659b
7
- data.tar.gz: 02fb8debb0d11f7b9d04f7616093535426f0ee5a0994992fcf3187ab00aa890dcd2fb248f14da49837508a3ccbb5756be208fc5d3b8dcd18ec6aaf0fb1bb1193
6
+ metadata.gz: 990972ebefe548f952cbf630708298f52c1856fa5a142a341f2548bd9173f03f0106d6b745c7e39cc5baa9f084d5fea5e4c0bf42cf1d42df94e404f3558d7816
7
+ data.tar.gz: e52615e0d5b7ca9d554ffc540fdfec524d2aed74ac1c7fc3c727d3096504aa81ff43a85b9e2ce7b21da87edf21ca5f92197171ff1b1c62fa85c7551839e9df83
data/CHANGELOG.md CHANGED
@@ -1,8 +1,53 @@
1
1
  # Unreleased
2
2
 
3
- # 4.8.1
3
+ # 5.0.6
4
4
 
5
- * Automatically reconnect after fork regardless of `reconnect_attempts`
5
+ - Wait for an extra `config.read_timeout` in blocking commands rather than an arbitrary 100ms. See #1175.
6
+ - Treat ReadOnlyError as ConnectionError. See #1168.
7
+
8
+ # 5.0.5
9
+
10
+ - Fix automatic disconnection when the process was forked. See #1157.
11
+
12
+ # 5.0.4
13
+
14
+ - Cast `ttl` argument to integer in `expire`, `setex` and a few others.
15
+
16
+ # 5.0.3
17
+
18
+ - Add `OutOfMemoryError` as a subclass of `CommandError`
19
+
20
+ # 5.0.2
21
+
22
+ - Fix `Redis#close` to properly reset the fork protection check.
23
+
24
+ # 5.0.1
25
+
26
+ - Added a fake `Redis::Connections.drivers` method to be compatible with older sidekiq versions.
27
+
28
+ # 5.0.0
29
+
30
+ - Eagerly and strictly cast Integer and Float parameters.
31
+ - Allow to call `subscribe`, `unsubscribe`, `psubscribe` and `punsubscribe` from a subscribed client. See #1131.
32
+ - Use `MD5` for hashing server nodes in `Redis::Distributed`. This should improve keys distribution among servers. See #1089.
33
+ - Changed `sadd` and `srem` to now always return an Integer.
34
+ - Added `sadd?` and `srem?` which always return a Boolean.
35
+ - Added support for `IDLE` paramter in `xpending`.
36
+ - Cluster support has been moved to a `redis-clustering` companion gem.
37
+ - `select` no longer record the current database. If the client has to reconnect after `select` was used, it will reconnect to the original database.
38
+ - Better support Float timeout in blocking commands. See #977.
39
+ - `Redis.new` will now raise an error if provided unknown options.
40
+ - Removed positional timeout in blocking commands (`BLPOP`, etc). Timeout now must be passed as an option: `r.blpop("key", timeout: 2.5)`
41
+ - Removed `logger` option.
42
+ - Removed `reconnect_delay_max` and `reconnect_delay`, you can pass precise sleep durations to `reconnect_attempts` instead.
43
+ - Require Ruby 2.5+.
44
+ - Removed the deprecated `queue` and `commit` methods. Use `pipelined` instead.
45
+ - Removed the deprecated `Redis::Future#==`.
46
+ - Removed the deprecated `pipelined` and `multi` signature. Commands now MUST be called on the block argument, not the original redis instance.
47
+ - Removed `Redis.current`. You shouldn't assume there is a single global Redis connection, use a connection pool instead,
48
+ and libaries using Redis should accept a Redis instance (or connection pool) as a config. E.g. `MyLibrary.redis = Redis.new(...)`.
49
+ - Removed the `synchrony` driver.
50
+ - Removed `Redis.exists_returns_integer`, it's now always enabled.
6
51
 
7
52
  # 4.8.0
8
53
 
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(host: 'mymaster', sentinels: SENTINELS, role: :master)
129
+ redis = Redis.new(name: 'mymaster', sentinels: SENTINELS, role: :master)
115
130
  ```
116
131
 
117
132
  ## Cluster support
118
133
 
119
- `redis-rb` supports [clustering](https://redis.io/topics/cluster-spec).
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 (since redis-rb 3.0). All calls on the pipeline object return a
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
- @set = pipeline.set "foo", "bar"
236
- @incr = pipeline.incr "baz"
195
+ set = pipeline.set "foo", "bar"
196
+ incr = pipeline.incr "baz"
237
197
  end
238
198
 
239
- @set.value
199
+ set.value
240
200
  # => "OK"
241
201
 
242
- @incr.value
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 StandardError => e
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
- The client allows you to configure how many `reconnect_attempts` it should
302
- complete before declaring a connection as failed. Furthermore, you may want
303
- to control the maximum duration between reconnection attempts with
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
- :reconnect_attempts => 10,
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
- The delay values are specified in seconds. With the above configuration, the
315
- client would attempt 10 reconnections, exponentially increasing the duration
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
- attempt_wait_time = [(reconnect_delay * 2**(attempt-1)), reconnect_delay_max].min
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
- **By default**, this gem will only **retry a connection once** and then fail, but with the
325
- above configuration the reconnection attempt would look like this:
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
- ## SSL/TLS Support
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
- This library supports natively terminating client side SSL/TLS connections
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
- [stunnel]: https://www.stunnel.org/
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
- ## Alternate drivers
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", "~> 3.0.1"
428
- gem "hiredis", "~> 0.4.5"
355
+ gem "redis"
356
+ gem "hiredis-client"
429
357
  ```
430
358
 
431
- When instantiating the client object, specify hiredis:
359
+ If your application doesn't call `Bundler.require`, you may have
360
+ to require it explictly:
432
361
 
433
362
  ```ruby
434
- redis = Redis.new(:driver => :hiredis)
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
- [em-synchrony]: https://github.com/igrigorik/em-synchrony
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
- When instantiating the client object, specify synchrony:
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(:driver => :synchrony)
372
+ redis = Redis.new(driver: :hiredis)
459
373
  ```
460
374
 
461
375
  ## Testing