redis 3.0.0 → 4.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +269 -0
  3. data/README.md +295 -58
  4. data/lib/redis.rb +1760 -451
  5. data/lib/redis/client.rb +355 -88
  6. data/lib/redis/cluster.rb +295 -0
  7. data/lib/redis/cluster/command.rb +81 -0
  8. data/lib/redis/cluster/command_loader.rb +34 -0
  9. data/lib/redis/cluster/key_slot_converter.rb +72 -0
  10. data/lib/redis/cluster/node.rb +107 -0
  11. data/lib/redis/cluster/node_key.rb +31 -0
  12. data/lib/redis/cluster/node_loader.rb +37 -0
  13. data/lib/redis/cluster/option.rb +90 -0
  14. data/lib/redis/cluster/slot.rb +86 -0
  15. data/lib/redis/cluster/slot_loader.rb +49 -0
  16. data/lib/redis/connection.rb +4 -2
  17. data/lib/redis/connection/command_helper.rb +5 -10
  18. data/lib/redis/connection/hiredis.rb +12 -8
  19. data/lib/redis/connection/registry.rb +2 -1
  20. data/lib/redis/connection/ruby.rb +232 -63
  21. data/lib/redis/connection/synchrony.rb +41 -14
  22. data/lib/redis/distributed.rb +205 -70
  23. data/lib/redis/errors.rb +48 -0
  24. data/lib/redis/hash_ring.rb +31 -73
  25. data/lib/redis/pipeline.rb +74 -18
  26. data/lib/redis/subscribe.rb +24 -13
  27. data/lib/redis/version.rb +3 -1
  28. metadata +63 -160
  29. data/.gitignore +0 -10
  30. data/.order +0 -169
  31. data/.travis.yml +0 -50
  32. data/.travis/Gemfile +0 -11
  33. data/.yardopts +0 -3
  34. data/Rakefile +0 -392
  35. data/benchmarking/logging.rb +0 -62
  36. data/benchmarking/pipeline.rb +0 -51
  37. data/benchmarking/speed.rb +0 -21
  38. data/benchmarking/suite.rb +0 -24
  39. data/benchmarking/worker.rb +0 -71
  40. data/examples/basic.rb +0 -15
  41. data/examples/dist_redis.rb +0 -43
  42. data/examples/incr-decr.rb +0 -17
  43. data/examples/list.rb +0 -26
  44. data/examples/pubsub.rb +0 -31
  45. data/examples/sets.rb +0 -36
  46. data/examples/unicorn/config.ru +0 -3
  47. data/examples/unicorn/unicorn.rb +0 -20
  48. data/redis.gemspec +0 -41
  49. data/test/blocking_commands_test.rb +0 -42
  50. data/test/command_map_test.rb +0 -30
  51. data/test/commands_on_hashes_test.rb +0 -21
  52. data/test/commands_on_lists_test.rb +0 -20
  53. data/test/commands_on_sets_test.rb +0 -77
  54. data/test/commands_on_sorted_sets_test.rb +0 -109
  55. data/test/commands_on_strings_test.rb +0 -83
  56. data/test/commands_on_value_types_test.rb +0 -99
  57. data/test/connection_handling_test.rb +0 -189
  58. data/test/db/.gitignore +0 -1
  59. data/test/distributed_blocking_commands_test.rb +0 -46
  60. data/test/distributed_commands_on_hashes_test.rb +0 -10
  61. data/test/distributed_commands_on_lists_test.rb +0 -22
  62. data/test/distributed_commands_on_sets_test.rb +0 -83
  63. data/test/distributed_commands_on_sorted_sets_test.rb +0 -18
  64. data/test/distributed_commands_on_strings_test.rb +0 -48
  65. data/test/distributed_commands_on_value_types_test.rb +0 -87
  66. data/test/distributed_commands_requiring_clustering_test.rb +0 -148
  67. data/test/distributed_connection_handling_test.rb +0 -23
  68. data/test/distributed_internals_test.rb +0 -15
  69. data/test/distributed_key_tags_test.rb +0 -52
  70. data/test/distributed_persistence_control_commands_test.rb +0 -26
  71. data/test/distributed_publish_subscribe_test.rb +0 -92
  72. data/test/distributed_remote_server_control_commands_test.rb +0 -53
  73. data/test/distributed_scripting_test.rb +0 -102
  74. data/test/distributed_sorting_test.rb +0 -20
  75. data/test/distributed_test.rb +0 -58
  76. data/test/distributed_transactions_test.rb +0 -32
  77. data/test/encoding_test.rb +0 -18
  78. data/test/error_replies_test.rb +0 -59
  79. data/test/helper.rb +0 -188
  80. data/test/helper_test.rb +0 -22
  81. data/test/internals_test.rb +0 -214
  82. data/test/lint/blocking_commands.rb +0 -124
  83. data/test/lint/hashes.rb +0 -162
  84. data/test/lint/lists.rb +0 -143
  85. data/test/lint/sets.rb +0 -96
  86. data/test/lint/sorted_sets.rb +0 -201
  87. data/test/lint/strings.rb +0 -157
  88. data/test/lint/value_types.rb +0 -106
  89. data/test/persistence_control_commands_test.rb +0 -26
  90. data/test/pipelining_commands_test.rb +0 -195
  91. data/test/publish_subscribe_test.rb +0 -153
  92. data/test/remote_server_control_commands_test.rb +0 -104
  93. data/test/scripting_test.rb +0 -78
  94. data/test/sorting_test.rb +0 -45
  95. data/test/support/connection/hiredis.rb +0 -1
  96. data/test/support/connection/ruby.rb +0 -1
  97. data/test/support/connection/synchrony.rb +0 -17
  98. data/test/support/redis_mock.rb +0 -92
  99. data/test/support/wire/synchrony.rb +0 -24
  100. data/test/support/wire/thread.rb +0 -5
  101. data/test/synchrony_driver.rb +0 -57
  102. data/test/test.conf +0 -9
  103. data/test/thread_safety_test.rb +0 -32
  104. data/test/transactions_test.rb +0 -244
  105. data/test/unknown_commands_test.rb +0 -14
  106. data/test/url_param_test.rb +0 -64
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 28eb23d20152436fc47f334f517c6fa62855e8e4711b44979cb05d86f8dcdd34
4
+ data.tar.gz: 46d01b3f5539800142582aeb7ebeabe4327bce970e31ce2048dcba027dfe6eb1
5
+ SHA512:
6
+ metadata.gz: f2f11269c6a3a030231eeb93dfa6bee54b340ff5ad244df6d79074c95f111e3d2081f49f77756576cb8225640e8b8cad144884c8519bcf1b0e7bedea3ca1b00f
7
+ data.tar.gz: 44ec06531632060b497cf1d02e6678c3d087ec3371cba86f53f9687848f73bb4e02c166b11d4db9e6b531b62ba2ca830649d71114063560f6dd764ca2ef10f07
@@ -1,3 +1,272 @@
1
+ # Unreleased
2
+
3
+ # 4.2.2
4
+
5
+ * Fix `WATCH` support for `Redis::Distributed`. See #941.
6
+ * Fix handling of empty stream responses. See #905, #929.
7
+
8
+ # 4.2.1
9
+
10
+ * Fix `exists?` returning an actual boolean when called with multiple keys. See #918.
11
+ * Setting `Redis.exists_returns_integer = false` disables warning message about new behaviour. See #920.
12
+
13
+ # 4.2.0
14
+
15
+ * Convert commands to accept keyword arguments rather than option hashes. This both help catching typos, and reduce needless allocations.
16
+ * Deprecate the synchrony driver. It will be removed in 5.0 and hopefully maintained as a separate gem. See #915.
17
+ * Make `Redis#exists` variadic, will return an Integer if called with multiple keys.
18
+ * Add `Redis#exists?` to get a Boolean if any of the keys exists.
19
+ * `Redis#exists` when called with a single key will warn that future versions will return an Integer.
20
+ Set `Redis.exists_returns_integer = true` to opt-in to the new behavior.
21
+ * Support `keepttl` ooption in `set`. See #913.
22
+ * Optimized initialization of Redis::Cluster. See #912.
23
+ * Accept sentinel options even with string key. See #599.
24
+ * Verify TLS connections by default. See #900.
25
+ * Make `Redis#hset` variadic. It now returns an integer, not a boolean. See #910.
26
+
27
+ # 4.1.4
28
+
29
+ * Alias `Redis#disconnect` as `#close`. See #901.
30
+ * Handle clusters with multiple slot ranges. See #894.
31
+ * Fix password authentication to a redis cluster. See #889.
32
+ * Handle recursive MOVED responses. See #882.
33
+ * Increase buffer size in the ruby connector. See #880.
34
+ * Fix thread safety of `Redis.queue`. See #878.
35
+ * Deprecate `Redis::Future#==` as it's likely to be a mistake. See #876.
36
+ * Support `KEEPTTL` option for SET command. See #913.
37
+
38
+ # 4.1.3
39
+
40
+ * Fix the client hanging forever when connecting with SSL to a non-SSL server. See #835.
41
+
42
+ # 4.1.2
43
+
44
+ * Fix several authentication problems with sentinel. See #850 and #856.
45
+ * Explicitly drop Ruby 2.2 support.
46
+
47
+
48
+ # 4.1.1
49
+
50
+ * Fix error handling in multi blocks. See #754.
51
+ * Fix geoadd to accept arrays like georadius and georadiusbymember. See #841.
52
+ * Fix georadius command failing when long == lat. See #841.
53
+ * Fix timeout error in xread block: 0. See #837.
54
+ * Fix incompatibility issue with redis-objects. See #834.
55
+ * Properly handle Errno::EADDRNOTAVAIL on connect.
56
+ * Fix password authentication to sentinel instances. See #813.
57
+
58
+ # 4.1.0
59
+
60
+ * Add Redis Cluster support. See #716.
61
+ * Add streams support. See #799 and #811.
62
+ * Add ZPOP* support. See #812.
63
+ * Fix issues with integer-like objects as BPOP timeout
64
+
65
+ # 4.0.3
66
+
67
+ * Fix raising command error for first command in pipeline. See #788.
68
+ * Fix the gemspec to stop exposing a `build` executable. See #785.
69
+ * Add `:reconnect_delay` and `:reconnect_delay_max` options. See #778.
70
+
71
+ # 4.0.2
72
+
73
+ * Added `Redis#unlink`. See #766.
74
+
75
+ * `Redis.new` now accept a custom connector via `:connector`. See #591.
76
+
77
+ * `Redis#multi` no longer perform empty transactions. See #747.
78
+
79
+ * `Redis#hdel` now accepts hash keys as multiple arguments like `#del`. See #755.
80
+
81
+ * Allow to skip SSL verification. See #745.
82
+
83
+ * Add Geo commands: `geoadd`, `geohash`, `georadius`, `georadiusbymember`, `geopos`, `geodist`. See #730.
84
+
85
+ # 4.0.1
86
+
87
+ * `Redis::Distributed` now supports `mget` and `mapped_mget`. See #687.
88
+
89
+ * `Redis::Distributed` now supports `sscan` and `sscan_each`. See #572.
90
+
91
+ * `Redis#connection` returns a hash with connection information.
92
+ You shouldn't need to call `Redis#_client`, ever.
93
+
94
+ * `Redis#flushdb` and `Redis#flushall` now support the `:async` option. See #706.
95
+
96
+
97
+ # 4.0
98
+
99
+ * Removed `Redis.connect`. Use `Redis.new`.
100
+
101
+ * Removed `Redis#[]` and `Redis#[]=` aliases.
102
+
103
+ * Added support for `CLIENT` commands. The lower-level client can be
104
+ accessed via `Redis#_client`.
105
+
106
+ * Dropped official support for Ruby < 2.2.2.
107
+
108
+ # 3.3.5
109
+
110
+ * Fixed Ruby 1.8 compatibility after backporting `Redis#connection`. See #719.
111
+
112
+ # 3.3.4 (yanked)
113
+
114
+ * `Redis#connection` returns a hash with connection information.
115
+ You shouldn't need to call `Redis#_client`, ever.
116
+
117
+ # 3.3.3
118
+
119
+ * Improved timeout handling after dropping Timeout module.
120
+
121
+ # 3.3.2
122
+
123
+ * Added support for `SPOP` with COUNT. See #628.
124
+
125
+ * Fixed connection glitches when using SSL. See #644.
126
+
127
+ # 3.3.1
128
+
129
+ * Remove usage of Timeout::timeout, refactor into using low level non-blocking writes.
130
+ This fixes a memory leak due to Timeout creating threads on each invocation.
131
+
132
+ # 3.3.0
133
+
134
+ * Added support for SSL/TLS. Redis doesn't support SSL natively, so you still
135
+ need to run a terminating proxy on Redis' side. See #496.
136
+
137
+ * Added `read_timeout` and `write_timeout` options. See #437, #482.
138
+
139
+ * Added support for pub/sub with timeouts. See #329.
140
+
141
+ * Added `Redis#call`, `Redis#queue` and `Redis#commit` as a more minimal API to
142
+ the client.
143
+
144
+ * Deprecated `Redis#disconnect!` in favor of `Redis#close`.
145
+
146
+ # 3.2.2
147
+
148
+ * Added support for `ZADD` options `NX`, `XX`, `CH`, `INCR`. See #547.
149
+
150
+ * Added support for sentinel commands. See #556.
151
+
152
+ * New `:id` option allows you to identify the client against Redis. See #510.
153
+
154
+ * `Redis::Distributed` will raise when adding two nodes with the same ID.
155
+ See #354.
156
+
157
+ # 3.2.1
158
+
159
+ * Added support for `PUBSUB` command.
160
+
161
+ * More low-level socket errors are now raised as `CannotConnectError`.
162
+
163
+ * Added `:connect_timeout` option.
164
+
165
+ * Added support for `:limit` option for `ZREVRANGEBYLEX`.
166
+
167
+ * Fixed an issue where connections become inconsistent when using Ruby's
168
+ Timeout module outside of the client (see #501, #502).
169
+
170
+ * Added `Redis#disconnect!` as a public-API way of disconnecting the client
171
+ (without needing to use `QUIT`). See #506.
172
+
173
+ * Fixed Sentinel support with Hiredis.
174
+
175
+ * Fixed Sentinel support when using authentication and databases.
176
+
177
+ * Improved resilience when trying to contact sentinels.
178
+
179
+ # 3.2.0
180
+
181
+ * Redis Sentinel support.
182
+
183
+ # 3.1.0
184
+
185
+ * Added debug log sanitization (#428).
186
+
187
+ * Added support for HyperLogLog commands (Redis 2.8.9, #432).
188
+
189
+ * Added support for `BITPOS` command (Redis 2.9.11, #412).
190
+
191
+ * The client will now automatically reconnect after a fork (#414).
192
+
193
+ * If you want to disable the fork-safety check and prefer to share the
194
+ connection across child processes, you can now pass the `inherit_socket`
195
+ option (#409).
196
+
197
+ * If you want the client to attempt to reconnect more than once, you can now
198
+ pass the `reconnect_attempts` option (#347)
199
+
200
+ # 3.0.7
201
+
202
+ * Added method `Redis#dup` to duplicate a Redis connection.
203
+
204
+ * IPv6 support.
205
+
206
+ # 3.0.6
207
+
208
+ * Added support for `SCAN` and variants.
209
+
210
+ # 3.0.5
211
+
212
+ * Fix calling #select from a pipeline (#309).
213
+
214
+ * Added method `Redis#connected?`.
215
+
216
+ * Added support for `MIGRATE` (Redis 2.6).
217
+
218
+ * Support extended SET command (#343, thanks to @benubois).
219
+
220
+ # 3.0.4
221
+
222
+ * Ensure #watch without a block returns "OK" (#332).
223
+
224
+ * Make futures identifiable (#330).
225
+
226
+ * Fix an issue preventing STORE in a SORT with multiple GETs (#328).
227
+
228
+ # 3.0.3
229
+
230
+ * Blocking list commands (`BLPOP`, `BRPOP`, `BRPOPLPUSH`) use a socket
231
+ timeout equal to the sum of the command's timeout and the Redis
232
+ client's timeout, instead of disabling socket timeout altogether.
233
+
234
+ * Ruby 2.0 compatibility.
235
+
236
+ * Added support for `DUMP` and `RESTORE` (Redis 2.6).
237
+
238
+ * Added support for `BITCOUNT` and `BITOP` (Redis 2.6).
239
+
240
+ * Call `#to_s` on value argument for `SET`, `SETEX`, `PSETEX`, `GETSET`,
241
+ `SETNX`, and `SETRANGE`.
242
+
243
+ # 3.0.2
244
+
245
+ * Unescape CGI escaped password in URL.
246
+
247
+ * Fix test to check availability of `UNIXSocket`.
248
+
249
+ * Fix handling of score = +/- infinity for sorted set commands.
250
+
251
+ * Replace array splats with concatenation where possible.
252
+
253
+ * Raise if `EXEC` returns an error.
254
+
255
+ * Passing a nil value in options hash no longer overwrites the default.
256
+
257
+ * Allow string keys in options hash passed to `Redis.new` or
258
+ `Redis.connect`.
259
+
260
+ * Fix uncaught error triggering unrelated error (synchrony driver).
261
+
262
+ See f7ffd5f1a628029691084de69e5b46699bb8b96d and #248.
263
+
264
+ # 3.0.1
265
+
266
+ * Fix reconnect logic not kicking in on a write error.
267
+
268
+ See 427dbd52928af452f35aa0a57b621bee56cdcb18 and #238.
269
+
1
270
  # 3.0.0
2
271
 
3
272
  ### Upgrading from 2.x to 3.0
data/README.md CHANGED
@@ -1,29 +1,17 @@
1
- # redis-rb [![Build Status][travis-image]][travis-link]
1
+ # redis-rb [![Build Status][travis-image]][travis-link] [![Inline docs][inchpages-image]][inchpages-link] ![](https://github.com/redis/redis-rb/workflows/Test/badge.svg?branch=master)
2
2
 
3
- [travis-image]: https://secure.travis-ci.org/redis/redis-rb.png?branch=master
4
- [travis-link]: http://travis-ci.org/redis/redis-rb
5
- [travis-home]: http://travis-ci.org/
3
+ A Ruby client that tries to match [Redis][redis-home]' API one-to-one, while still
4
+ providing an idiomatic interface.
6
5
 
7
- A Ruby client library for [Redis][redis-home].
8
-
9
- [redis-home]: http://redis.io
10
-
11
- A Ruby client that tries to match Redis' API one-to-one, while still
12
- providing an idiomatic interface. It features thread-safety, client-side
13
- sharding, pipelining, and an obsession for performance.
14
-
15
- ## Upgrading from 2.x to 3.0
16
-
17
- Please refer to the [CHANGELOG][changelog-3.0.0] for a summary of the
18
- most important changes, as well as a full list of changes.
19
-
20
- [changelog-3.0.0]: https://github.com/redis/redis-rb/blob/master/CHANGELOG.md#300
6
+ See [RubyDoc.info][rubydoc] for the API docs of the latest published gem.
21
7
 
22
8
  ## Getting started
23
9
 
24
- As of version 2.0 this client only targets Redis version 2.0 and higher.
25
- You can use an older version of this client if you need to interface
26
- with a Redis instance older than 2.0, but this is no longer supported.
10
+ Install with:
11
+
12
+ ```
13
+ $ gem install redis
14
+ ```
27
15
 
28
16
  You can connect to Redis by instantiating the `Redis` class:
29
17
 
@@ -33,18 +21,37 @@ require "redis"
33
21
  redis = Redis.new
34
22
  ```
35
23
 
36
- This assumes Redis was started with a default configuration, and it
24
+ This assumes Redis was started with a default configuration, and is
37
25
  listening on `localhost`, port 6379. If you need to connect to a remote
38
26
  server or a different port, try:
39
27
 
40
28
  ```ruby
41
- redis = Redis.new(:host => "10.0.1.1", :port => 6380)
29
+ redis = Redis.new(host: "10.0.1.1", port: 6380, db: 15)
30
+ ```
31
+
32
+ You can also specify connection options as a [`redis://` URL][redis-url]:
33
+
34
+ ```ruby
35
+ redis = Redis.new(url: "redis://:p4ssw0rd@10.0.1.1:6380/15")
42
36
  ```
43
37
 
38
+ The client expects passwords with special chracters to be URL-encoded (i.e.
39
+ `CGI.escape(password)`).
40
+
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
+
44
45
  To connect to Redis listening on a Unix socket, try:
45
46
 
46
47
  ```ruby
47
- redis = Redis.new(:path => "/tmp/redis.sock")
48
+ redis = Redis.new(path: "/tmp/redis.sock")
49
+ ```
50
+
51
+ To connect to a password protected Redis instance, use:
52
+
53
+ ```ruby
54
+ redis = Redis.new(password: "mysecret")
48
55
  ```
49
56
 
50
57
  The Redis class exports methods that are named identical to the commands
@@ -52,8 +59,6 @@ they execute. The arguments these methods accept are often identical to
52
59
  the arguments specified on the [Redis website][redis-commands]. For
53
60
  instance, the `SET` and `GET` commands can be called like this:
54
61
 
55
- [redis-commands]: http://redis.io/commands
56
-
57
62
  ```ruby
58
63
  redis.set("mykey", "hello world")
59
64
  # => "OK"
@@ -62,15 +67,92 @@ redis.get("mykey")
62
67
  # => "hello world"
63
68
  ```
64
69
 
65
- All commands, their arguments and return values are documented, and
66
- available on [rdoc.info][rdoc].
70
+ All commands, their arguments, and return values are documented and
71
+ available on [RubyDoc.info][rubydoc].
72
+
73
+ ## Sentinel support
74
+
75
+ The client is able to perform automatic failover by using [Redis
76
+ Sentinel](http://redis.io/topics/sentinel). Make sure to run Redis 2.8+
77
+ if you want to use this feature.
78
+
79
+ To connect using Sentinel, use:
80
+
81
+ ```ruby
82
+ SENTINELS = [{ host: "127.0.0.1", port: 26380 },
83
+ { host: "127.0.0.1", port: 26381 }]
84
+
85
+ redis = Redis.new(url: "redis://mymaster", sentinels: SENTINELS, role: :master)
86
+ ```
87
+
88
+ * The master name identifies a group of Redis instances composed of a master
89
+ and one or more slaves (`mymaster` in the example).
90
+
91
+ * It is possible to optionally provide a role. The allowed roles are `master`
92
+ and `slave`. When the role is `slave`, the client will try to connect to a
93
+ random slave of the specified master. If a role is not specified, the client
94
+ will connect to the master.
95
+
96
+ * When using the Sentinel support you need to specify a list of sentinels to
97
+ connect to. The list does not need to enumerate all your Sentinel instances,
98
+ but a few so that if one is down the client will try the next one. The client
99
+ is able to remember the last Sentinel that was able to reply correctly and will
100
+ use it for the next requests.
101
+
102
+ If you want to [authenticate](https://redis.io/topics/sentinel#configuring-sentinel-instances-with-authentication) Sentinel itself, you must specify the `password` option per instance.
103
+
104
+ ```ruby
105
+ SENTINELS = [{ host: '127.0.0.1', port: 26380, password: 'mysecret' },
106
+ { host: '127.0.0.1', port: 26381, password: 'mysecret' }]
107
+
108
+ redis = Redis.new(host: 'mymaster', sentinels: SENTINELS, role: :master)
109
+ ```
110
+
111
+ ## Cluster support
112
+
113
+ `redis-rb` supports [clustering](https://redis.io/topics/cluster-spec).
114
+
115
+ ```ruby
116
+ # Nodes can be passed to the client as an array of connection URLs.
117
+ nodes = (7000..7005).map { |port| "redis://127.0.0.1:#{port}" }
118
+ redis = Redis.new(cluster: nodes)
119
+
120
+ # You can also specify the options as a Hash. The options are the same as for a single server connection.
121
+ (7000..7005).map { |port| { host: '127.0.0.1', port: port } }
122
+ ```
123
+
124
+ 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.
125
+
126
+ ```ruby
127
+ Redis.new(cluster: %w[redis://127.0.0.1:7000])
128
+ ```
129
+
130
+ 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.
131
+
132
+ ```ruby
133
+ Redis.new(cluster: nodes, replica: true)
134
+ ```
135
+
136
+ The calling code is responsible for [avoiding cross slot commands](https://redis.io/topics/cluster-spec#keys-distribution-model).
137
+
138
+ ```ruby
139
+ redis = Redis.new(cluster: %w[redis://127.0.0.1:7000])
140
+
141
+ redis.mget('key1', 'key2')
142
+ #=> Redis::CommandError (CROSSSLOT Keys in request don't hash to the same slot)
67
143
 
68
- [rdoc]: http://rdoc.info/github/redis/redis-rb/
144
+ redis.mget('{key}1', '{key}2')
145
+ #=> [nil, nil]
146
+ ```
147
+
148
+ * The client automatically reconnects after a failover occurred, but the caller is responsible for handling errors while it is happening.
149
+ * The client support permanent node failures, and will reroute requests to promoted slaves.
150
+ * The client supports `MOVED` and `ASK` redirections transparently.
69
151
 
70
152
  ## Storing objects
71
153
 
72
- Redis only stores strings as values. If you want to store an object, you
73
- can use a serialization mechanism such as JSON:
154
+ Redis "string" types can be used to store serialized Ruby objects, for
155
+ example with JSON:
74
156
 
75
157
  ```ruby
76
158
  require "json"
@@ -124,7 +206,7 @@ end
124
206
  Replies to commands in a pipeline can be accessed via the *futures* they
125
207
  emit (since redis-rb 3.0). All calls inside a pipeline block return a
126
208
  `Future` object, which responds to the `#value` method. When the
127
- pipeline has succesfully executed, all futures are assigned their
209
+ pipeline has successfully executed, all futures are assigned their
128
210
  respective replies and can be used.
129
211
 
130
212
  ```ruby
@@ -140,6 +222,163 @@ end
140
222
  # => 1
141
223
  ```
142
224
 
225
+ ## Error Handling
226
+
227
+ In general, if something goes wrong you'll get an exception. For example, if
228
+ it can't connect to the server a `Redis::CannotConnectError` error will be raised.
229
+
230
+ ```ruby
231
+ begin
232
+ redis.ping
233
+ rescue StandardError => e
234
+ e.inspect
235
+ # => #<Redis::CannotConnectError: Timed out connecting to Redis on 10.0.1.1:6380>
236
+
237
+ e.message
238
+ # => Timed out connecting to Redis on 10.0.1.1:6380
239
+ end
240
+ ```
241
+
242
+ See lib/redis/errors.rb for information about what exceptions are possible.
243
+
244
+ ## Timeouts
245
+
246
+ The client allows you to configure connect, read, and write timeouts.
247
+ Passing a single `timeout` option will set all three values:
248
+
249
+ ```ruby
250
+ Redis.new(:timeout => 1)
251
+ ```
252
+
253
+ But you can use specific values for each of them:
254
+
255
+ ```ruby
256
+ Redis.new(
257
+ :connect_timeout => 0.2,
258
+ :read_timeout => 1.0,
259
+ :write_timeout => 0.5
260
+ )
261
+ ```
262
+
263
+ All timeout values are specified in seconds.
264
+
265
+ When using pub/sub, you can subscribe to a channel using a timeout as well:
266
+
267
+ ```ruby
268
+ redis.subscribe_with_timeout(5, "news") do |on|
269
+ on.message do |channel, message|
270
+ # ...
271
+ end
272
+ end
273
+ ```
274
+
275
+ If no message is received after 5 seconds, the client will unsubscribe.
276
+
277
+ ## Reconnections
278
+
279
+ The client allows you to configure how many `reconnect_attempts` it should
280
+ complete before declaring a connection as failed. Furthermore, you may want
281
+ to control the maximum duration between reconnection attempts with
282
+ `reconnect_delay` and `reconnect_delay_max`.
283
+
284
+ ```ruby
285
+ Redis.new(
286
+ :reconnect_attempts => 10,
287
+ :reconnect_delay => 1.5,
288
+ :reconnect_delay_max => 10.0,
289
+ )
290
+ ```
291
+
292
+ The delay values are specified in seconds. With the above configuration, the
293
+ client would attempt 10 reconnections, exponentially increasing the duration
294
+ between each attempt but it never waits longer than `reconnect_delay_max`.
295
+
296
+ This is the retry algorithm:
297
+
298
+ ```ruby
299
+ attempt_wait_time = [(reconnect_delay * 2**(attempt-1)), reconnect_delay_max].min
300
+ ```
301
+
302
+ **By default**, this gem will only **retry a connection once** and then fail, but with the
303
+ above configuration the reconnection attempt would look like this:
304
+
305
+ #|Attempt wait time|Total wait time
306
+ :-:|:-:|:-:
307
+ 1|1.5s|1.5s
308
+ 2|3.0s|4.5s
309
+ 3|6.0s|10.5s
310
+ 4|10.0s|20.5s
311
+ 5|10.0s|30.5s
312
+ 6|10.0s|40.5s
313
+ 7|10.0s|50.5s
314
+ 8|10.0s|60.5s
315
+ 9|10.0s|70.5s
316
+ 10|10.0s|80.5s
317
+
318
+ So if the reconnection attempt #10 succeeds 70 seconds have elapsed trying
319
+ to reconnect, this is likely fine in long-running background processes, but if
320
+ you use Redis to drive your website you might want to have a lower
321
+ `reconnect_delay_max` or have less `reconnect_attempts`.
322
+
323
+ ## SSL/TLS Support
324
+
325
+ This library supports natively terminating client side SSL/TLS connections
326
+ when talking to Redis via a server-side proxy such as [stunnel], [hitch],
327
+ or [ghostunnel].
328
+
329
+ To enable SSL support, pass the `:ssl => true` option when configuring the
330
+ Redis client, or pass in `:url => "rediss://..."` (like HTTPS for Redis).
331
+ You will also need to pass in an `:ssl_params => { ... }` hash used to
332
+ configure the `OpenSSL::SSL::SSLContext` object used for the connection:
333
+
334
+ ```ruby
335
+ redis = Redis.new(
336
+ :url => "rediss://:p4ssw0rd@10.0.1.1:6381/15",
337
+ :ssl_params => {
338
+ :ca_file => "/path/to/ca.crt"
339
+ }
340
+ )
341
+ ```
342
+
343
+ The options given to `:ssl_params` are passed directly to the
344
+ `OpenSSL::SSL::SSLContext#set_params` method and can be any valid attribute
345
+ of the SSL context. Please see the [OpenSSL::SSL::SSLContext documentation]
346
+ for all of the available attributes.
347
+
348
+ Here is an example of passing in params that can be used for SSL client
349
+ certificate authentication (a.k.a. mutual TLS):
350
+
351
+ ```ruby
352
+ redis = Redis.new(
353
+ :url => "rediss://:p4ssw0rd@10.0.1.1:6381/15",
354
+ :ssl_params => {
355
+ :ca_file => "/path/to/ca.crt",
356
+ :cert => OpenSSL::X509::Certificate.new(File.read("client.crt")),
357
+ :key => OpenSSL::PKey::RSA.new(File.read("client.key"))
358
+ }
359
+ )
360
+ ```
361
+
362
+ [stunnel]: https://www.stunnel.org/
363
+ [hitch]: https://hitch-tls.org/
364
+ [ghostunnel]: https://github.com/square/ghostunnel
365
+ [OpenSSL::SSL::SSLContext documentation]: http://ruby-doc.org/stdlib-2.3.0/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html
366
+
367
+ *NOTE:* SSL is only supported by the default "Ruby" driver
368
+
369
+
370
+ ## Expert-Mode Options
371
+
372
+ - `inherit_socket: true`: disable safety check that prevents a forked child
373
+ from sharing a socket with its parent; this is potentially useful in order to mitigate connection churn when:
374
+ - many short-lived forked children of one process need to talk
375
+ to redis, AND
376
+ - your own code prevents the parent process from using the redis
377
+ connection while a child is alive
378
+
379
+ Improper use of `inherit_socket` will result in corrupted and/or incorrect
380
+ responses.
381
+
143
382
  ## Alternate drivers
144
383
 
145
384
  By default, redis-rb uses Ruby's socket library to talk with Redis.
@@ -163,7 +402,7 @@ It is best to use hiredis when you have large replies (for example:
163
402
  In your Gemfile, include hiredis:
164
403
 
165
404
  ```ruby
166
- gem "redis", "~> 3.0.0.rc2"
405
+ gem "redis", "~> 3.0.1"
167
406
  gem "hiredis", "~> 0.4.5"
168
407
  ```
169
408
 
@@ -186,12 +425,12 @@ protocol.
186
425
  In your Gemfile, include em-synchrony and hiredis:
187
426
 
188
427
  ```ruby
189
- gem "redis", "~> 3.0.0.rc2"
428
+ gem "redis", "~> 3.0.1"
190
429
  gem "hiredis", "~> 0.4.5"
191
430
  gem "em-synchrony"
192
431
  ```
193
432
 
194
- When instantiating the client object, specify hiredis:
433
+ When instantiating the client object, specify synchrony:
195
434
 
196
435
  ```ruby
197
436
  redis = Redis.new(:driver => :synchrony)
@@ -199,34 +438,32 @@ redis = Redis.new(:driver => :synchrony)
199
438
 
200
439
  ## Testing
201
440
 
202
- This library is tested using [Travis][travis-home], where it is tested
203
- against the following interpreters and drivers:
441
+ This library is tested against recent Ruby and Redis versions.
442
+ Check [Travis][travis-link] for the exact versions supported.
443
+
444
+ ## See Also
204
445
 
205
- * MRI 1.8.7 (drivers: ruby, hiredis)
206
- * MRI 1.9.2 (drivers: ruby, hiredis, synchrony)
207
- * MRI 1.9.3 (drivers: ruby, hiredis, synchrony)
208
- * JRuby 1.6 (1.8 mode) (drivers: ruby)
209
- * JRuby 1.6 (1.9 mode) (drivers: ruby)
446
+ - [async-redis](https://github.com/socketry/async-redis) — An [async](https://github.com/socketry/async) compatible Redis client.
210
447
 
211
448
  ## Contributors
212
449
 
213
- (ordered chronologically with more than 5 commits, see `git shortlog -sn` for
214
- all contributors)
215
-
216
- * Ezra Zygmuntowicz
217
- * Taylor Weibley
218
- * Matthew Clark
219
- * Brian McKinney
220
- * Luca Guidi
221
- * Salvatore Sanfillipo
222
- * Chris Wanstrath
223
- * Damian Janowski
224
- * Michel Martens
225
- * Nick Quaranto
226
- * Pieter Noordhuis
227
- * Ilya Grigorik
450
+ Several people contributed to redis-rb, but we would like to especially
451
+ mention Ezra Zygmuntowicz. Ezra introduced the Ruby community to many
452
+ new cool technologies, like Redis. He wrote the first version of this
453
+ client and evangelized Redis in Rubyland. Thank you, Ezra.
228
454
 
229
455
  ## Contributing
230
456
 
231
457
  [Fork the project](https://github.com/redis/redis-rb) and send pull
232
- requests. You can also ask for help at `#redis-rb` on Freenode.
458
+ requests.
459
+
460
+
461
+ [inchpages-image]: https://inch-ci.org/github/redis/redis-rb.svg
462
+ [inchpages-link]: https://inch-ci.org/github/redis/redis-rb
463
+ [redis-commands]: https://redis.io/commands
464
+ [redis-home]: https://redis.io
465
+ [redis-url]: http://www.iana.org/assignments/uri-schemes/prov/redis
466
+ [travis-home]: https://travis-ci.org/
467
+ [travis-image]: https://secure.travis-ci.org/redis/redis-rb.svg?branch=master
468
+ [travis-link]: https://travis-ci.org/redis/redis-rb
469
+ [rubydoc]: http://www.rubydoc.info/gems/redis