redis 3.2.2 → 4.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +175 -13
  3. data/README.md +223 -76
  4. data/lib/redis.rb +1360 -445
  5. data/lib/redis/client.rb +183 -103
  6. data/lib/redis/cluster.rb +291 -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 +108 -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 +93 -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 +9 -6
  19. data/lib/redis/connection/registry.rb +2 -1
  20. data/lib/redis/connection/ruby.rb +168 -63
  21. data/lib/redis/connection/synchrony.rb +29 -7
  22. data/lib/redis/distributed.rb +156 -74
  23. data/lib/redis/errors.rb +48 -0
  24. data/lib/redis/hash_ring.rb +30 -73
  25. data/lib/redis/pipeline.rb +55 -15
  26. data/lib/redis/subscribe.rb +20 -13
  27. data/lib/redis/version.rb +3 -1
  28. metadata +41 -170
  29. data/.gitignore +0 -16
  30. data/.travis.yml +0 -59
  31. data/.travis/Gemfile +0 -11
  32. data/.yardopts +0 -3
  33. data/Gemfile +0 -4
  34. data/Rakefile +0 -87
  35. data/benchmarking/logging.rb +0 -71
  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/consistency.rb +0 -114
  42. data/examples/dist_redis.rb +0 -43
  43. data/examples/incr-decr.rb +0 -17
  44. data/examples/list.rb +0 -26
  45. data/examples/pubsub.rb +0 -37
  46. data/examples/sentinel.rb +0 -41
  47. data/examples/sentinel/sentinel.conf +0 -9
  48. data/examples/sentinel/start +0 -49
  49. data/examples/sets.rb +0 -36
  50. data/examples/unicorn/config.ru +0 -3
  51. data/examples/unicorn/unicorn.rb +0 -20
  52. data/redis.gemspec +0 -44
  53. data/test/bitpos_test.rb +0 -69
  54. data/test/blocking_commands_test.rb +0 -42
  55. data/test/command_map_test.rb +0 -30
  56. data/test/commands_on_hashes_test.rb +0 -21
  57. data/test/commands_on_hyper_log_log_test.rb +0 -21
  58. data/test/commands_on_lists_test.rb +0 -20
  59. data/test/commands_on_sets_test.rb +0 -77
  60. data/test/commands_on_sorted_sets_test.rb +0 -137
  61. data/test/commands_on_strings_test.rb +0 -101
  62. data/test/commands_on_value_types_test.rb +0 -133
  63. data/test/connection_handling_test.rb +0 -250
  64. data/test/db/.gitkeep +0 -0
  65. data/test/distributed_blocking_commands_test.rb +0 -46
  66. data/test/distributed_commands_on_hashes_test.rb +0 -10
  67. data/test/distributed_commands_on_hyper_log_log_test.rb +0 -33
  68. data/test/distributed_commands_on_lists_test.rb +0 -22
  69. data/test/distributed_commands_on_sets_test.rb +0 -83
  70. data/test/distributed_commands_on_sorted_sets_test.rb +0 -18
  71. data/test/distributed_commands_on_strings_test.rb +0 -59
  72. data/test/distributed_commands_on_value_types_test.rb +0 -95
  73. data/test/distributed_commands_requiring_clustering_test.rb +0 -164
  74. data/test/distributed_connection_handling_test.rb +0 -23
  75. data/test/distributed_internals_test.rb +0 -79
  76. data/test/distributed_key_tags_test.rb +0 -52
  77. data/test/distributed_persistence_control_commands_test.rb +0 -26
  78. data/test/distributed_publish_subscribe_test.rb +0 -92
  79. data/test/distributed_remote_server_control_commands_test.rb +0 -66
  80. data/test/distributed_scripting_test.rb +0 -102
  81. data/test/distributed_sorting_test.rb +0 -20
  82. data/test/distributed_test.rb +0 -58
  83. data/test/distributed_transactions_test.rb +0 -32
  84. data/test/encoding_test.rb +0 -18
  85. data/test/error_replies_test.rb +0 -59
  86. data/test/fork_safety_test.rb +0 -65
  87. data/test/helper.rb +0 -232
  88. data/test/helper_test.rb +0 -24
  89. data/test/internals_test.rb +0 -437
  90. data/test/lint/blocking_commands.rb +0 -150
  91. data/test/lint/hashes.rb +0 -162
  92. data/test/lint/hyper_log_log.rb +0 -60
  93. data/test/lint/lists.rb +0 -143
  94. data/test/lint/sets.rb +0 -125
  95. data/test/lint/sorted_sets.rb +0 -316
  96. data/test/lint/strings.rb +0 -260
  97. data/test/lint/value_types.rb +0 -122
  98. data/test/persistence_control_commands_test.rb +0 -26
  99. data/test/pipelining_commands_test.rb +0 -242
  100. data/test/publish_subscribe_test.rb +0 -254
  101. data/test/remote_server_control_commands_test.rb +0 -118
  102. data/test/scanning_test.rb +0 -413
  103. data/test/scripting_test.rb +0 -78
  104. data/test/sentinel_command_test.rb +0 -80
  105. data/test/sentinel_test.rb +0 -255
  106. data/test/sorting_test.rb +0 -59
  107. data/test/support/connection/hiredis.rb +0 -1
  108. data/test/support/connection/ruby.rb +0 -1
  109. data/test/support/connection/synchrony.rb +0 -17
  110. data/test/support/redis_mock.rb +0 -119
  111. data/test/support/wire/synchrony.rb +0 -24
  112. data/test/support/wire/thread.rb +0 -5
  113. data/test/synchrony_driver.rb +0 -88
  114. data/test/test.conf.erb +0 -9
  115. data/test/thread_safety_test.rb +0 -32
  116. data/test/transactions_test.rb +0 -264
  117. data/test/unknown_commands_test.rb +0 -14
  118. data/test/url_param_test.rb +0 -138
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 183e90b7d3961182b8b5b20b1295b6dd9d30df12
4
- data.tar.gz: 60023071a61af0e34d85b0a999db0bc5877070ad
2
+ SHA256:
3
+ metadata.gz: d5ff2ee4b6a6f2b087ac26bf96a3c1769cf42f70ea90008361157f7ef04cdb14
4
+ data.tar.gz: f2c24654294c4fa81a5cff4ddb545bc59e6f85b64ee61273278cb1e286a4edb8
5
5
  SHA512:
6
- metadata.gz: a1d93f8ee26f3dfecb10d223d178e4f78aa399d3bc8a78a4db479f0e6d89bd77c97d9e113b0138d102fbecf3d0a4452ce5f0da9412e069726c3b1fd7bb7bf7a4
7
- data.tar.gz: 1a2077544497d0f2a1cd9035677dc1d514a9395b070b10f380e8fcc35cbbbbbae898e1b4ad3e7ff44e2fb96930330cb66b021ccaa726451c2c15276ff26b0011
6
+ metadata.gz: 0d88c6621659a178dca04d3ca62f25520f5f1a846b6300f93fb008966551fb4795a3e6c37810f99ea18f77a6292b955fa180ae3e06f8c90df7e6a3ca27087ae1
7
+ data.tar.gz: 1427cc268e867872388f214184d23a5c6062104fcb9d1e50d6026dd9daf6e51b9833866fee9fcf80c7a64e4de705295de8399d8e8ac22fa890bf358bd63ff707
data/CHANGELOG.md CHANGED
@@ -1,16 +1,178 @@
1
- # 4.x (unreleased)
2
-
3
- ## Planned breaking changes:
4
- * `Redis#client` will no longer expose the underlying `Redis::Client`;
5
- it has not yet been determined how 4.0 will expose the underlying
6
- functionality, but we will make every attempt to provide a final minor
7
- release of 3.x that provides the new interfaces in order to facilitate
8
- a smooth transition.
9
-
10
- * Ruby 1.8.7 (and the 1.8 modes of JRuby and Rubinius) will no longer be
11
- supported; 1.8.x entered end-of-life in June of 2012 and stopped receiving
12
- security updates in June of 2013; continuing to support it would prevent
13
- the use of newer features of Ruby.
1
+ # Unreleased
2
+
3
+ # 4.4.0
4
+
5
+ * Redis cluster: fix cross-slot validation in pipelines. Fix ##1019.
6
+ * Add support for `XAUTOCLAIM`. See #1018.
7
+ * Properly issue `READONLY` when reconnecting to replicas. Fix #1017.
8
+ * Make `del` a noop if passed an empty list of keys. See #998.
9
+ * Add support for `ZINTER`. See #995.
10
+
11
+ # 4.3.1
12
+
13
+ * Fix password authentication against redis server 5 and older.
14
+
15
+ # 4.3.0
16
+
17
+ * Add the TYPE argument to scan and scan_each. See #985.
18
+ * Support AUTH command for ACL. See #967.
19
+
20
+ # 4.2.5
21
+
22
+ * Optimize the ruby connector write buffering. See #964.
23
+
24
+ # 4.2.4
25
+
26
+ * Fix bytesize calculations in the ruby connector, and work on a copy of the buffer. Fix #961, #962.
27
+
28
+ # 4.2.3
29
+
30
+ * Use io/wait instead of IO.select in the ruby connector. See #960.
31
+ * Use exception free non blocking IOs in the ruby connector. See #926.
32
+ * Prevent corruption of the client when an interrupt happen during inside a pipeline block. See #945.
33
+
34
+ # 4.2.2
35
+
36
+ * Fix `WATCH` support for `Redis::Distributed`. See #941.
37
+ * Fix handling of empty stream responses. See #905, #929.
38
+
39
+ # 4.2.1
40
+
41
+ * Fix `exists?` returning an actual boolean when called with multiple keys. See #918.
42
+ * Setting `Redis.exists_returns_integer = false` disables warning message about new behaviour. See #920.
43
+
44
+ # 4.2.0
45
+
46
+ * Convert commands to accept keyword arguments rather than option hashes. This both help catching typos, and reduce needless allocations.
47
+ * Deprecate the synchrony driver. It will be removed in 5.0 and hopefully maintained as a separate gem. See #915.
48
+ * Make `Redis#exists` variadic, will return an Integer if called with multiple keys.
49
+ * Add `Redis#exists?` to get a Boolean if any of the keys exists.
50
+ * `Redis#exists` when called with a single key will warn that future versions will return an Integer.
51
+ Set `Redis.exists_returns_integer = true` to opt-in to the new behavior.
52
+ * Support `keepttl` ooption in `set`. See #913.
53
+ * Optimized initialization of Redis::Cluster. See #912.
54
+ * Accept sentinel options even with string key. See #599.
55
+ * Verify TLS connections by default. See #900.
56
+ * Make `Redis#hset` variadic. It now returns an integer, not a boolean. See #910.
57
+
58
+ # 4.1.4
59
+
60
+ * Alias `Redis#disconnect` as `#close`. See #901.
61
+ * Handle clusters with multiple slot ranges. See #894.
62
+ * Fix password authentication to a redis cluster. See #889.
63
+ * Handle recursive MOVED responses. See #882.
64
+ * Increase buffer size in the ruby connector. See #880.
65
+ * Fix thread safety of `Redis.queue`. See #878.
66
+ * Deprecate `Redis::Future#==` as it's likely to be a mistake. See #876.
67
+ * Support `KEEPTTL` option for SET command. See #913.
68
+
69
+ # 4.1.3
70
+
71
+ * Fix the client hanging forever when connecting with SSL to a non-SSL server. See #835.
72
+
73
+ # 4.1.2
74
+
75
+ * Fix several authentication problems with sentinel. See #850 and #856.
76
+ * Explicitly drop Ruby 2.2 support.
77
+
78
+
79
+ # 4.1.1
80
+
81
+ * Fix error handling in multi blocks. See #754.
82
+ * Fix geoadd to accept arrays like georadius and georadiusbymember. See #841.
83
+ * Fix georadius command failing when long == lat. See #841.
84
+ * Fix timeout error in xread block: 0. See #837.
85
+ * Fix incompatibility issue with redis-objects. See #834.
86
+ * Properly handle Errno::EADDRNOTAVAIL on connect.
87
+ * Fix password authentication to sentinel instances. See #813.
88
+
89
+ # 4.1.0
90
+
91
+ * Add Redis Cluster support. See #716.
92
+ * Add streams support. See #799 and #811.
93
+ * Add ZPOP* support. See #812.
94
+ * Fix issues with integer-like objects as BPOP timeout
95
+
96
+ # 4.0.3
97
+
98
+ * Fix raising command error for first command in pipeline. See #788.
99
+ * Fix the gemspec to stop exposing a `build` executable. See #785.
100
+ * Add `:reconnect_delay` and `:reconnect_delay_max` options. See #778.
101
+
102
+ # 4.0.2
103
+
104
+ * Added `Redis#unlink`. See #766.
105
+
106
+ * `Redis.new` now accept a custom connector via `:connector`. See #591.
107
+
108
+ * `Redis#multi` no longer perform empty transactions. See #747.
109
+
110
+ * `Redis#hdel` now accepts hash keys as multiple arguments like `#del`. See #755.
111
+
112
+ * Allow to skip SSL verification. See #745.
113
+
114
+ * Add Geo commands: `geoadd`, `geohash`, `georadius`, `georadiusbymember`, `geopos`, `geodist`. See #730.
115
+
116
+ # 4.0.1
117
+
118
+ * `Redis::Distributed` now supports `mget` and `mapped_mget`. See #687.
119
+
120
+ * `Redis::Distributed` now supports `sscan` and `sscan_each`. See #572.
121
+
122
+ * `Redis#connection` returns a hash with connection information.
123
+ You shouldn't need to call `Redis#_client`, ever.
124
+
125
+ * `Redis#flushdb` and `Redis#flushall` now support the `:async` option. See #706.
126
+
127
+
128
+ # 4.0
129
+
130
+ * Removed `Redis.connect`. Use `Redis.new`.
131
+
132
+ * Removed `Redis#[]` and `Redis#[]=` aliases.
133
+
134
+ * Added support for `CLIENT` commands. The lower-level client can be
135
+ accessed via `Redis#_client`.
136
+
137
+ * Dropped official support for Ruby < 2.2.2.
138
+
139
+ # 3.3.5
140
+
141
+ * Fixed Ruby 1.8 compatibility after backporting `Redis#connection`. See #719.
142
+
143
+ # 3.3.4 (yanked)
144
+
145
+ * `Redis#connection` returns a hash with connection information.
146
+ You shouldn't need to call `Redis#_client`, ever.
147
+
148
+ # 3.3.3
149
+
150
+ * Improved timeout handling after dropping Timeout module.
151
+
152
+ # 3.3.2
153
+
154
+ * Added support for `SPOP` with COUNT. See #628.
155
+
156
+ * Fixed connection glitches when using SSL. See #644.
157
+
158
+ # 3.3.1
159
+
160
+ * Remove usage of Timeout::timeout, refactor into using low level non-blocking writes.
161
+ This fixes a memory leak due to Timeout creating threads on each invocation.
162
+
163
+ # 3.3.0
164
+
165
+ * Added support for SSL/TLS. Redis doesn't support SSL natively, so you still
166
+ need to run a terminating proxy on Redis' side. See #496.
167
+
168
+ * Added `read_timeout` and `write_timeout` options. See #437, #482.
169
+
170
+ * Added support for pub/sub with timeouts. See #329.
171
+
172
+ * Added `Redis#call`, `Redis#queue` and `Redis#commit` as a more minimal API to
173
+ the client.
174
+
175
+ * Deprecated `Redis#disconnect!` in favor of `Redis#close`.
14
176
 
15
177
  # 3.2.2
16
178
 
data/README.md CHANGED
@@ -1,46 +1,18 @@
1
- # redis-rb [![Build Status][travis-image]][travis-link] [![Inline docs][inchpages-image]][inchpages-link]
1
+ # redis-rb [![Build Status][gh-actions-image]][gh-actions-link] [![Inline docs][inchpages-image]][inchpages-link]
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/
6
- [inchpages-image]: http://inch-ci.org/github/redis/redis-rb.png
7
- [inchpages-link]: http://inch-ci.org/github/redis/redis-rb
3
+ A Ruby client that tries to match [Redis][redis-home]' API one-to-one, while still
4
+ providing an idiomatic interface.
8
5
 
9
- A Ruby client library for [Redis][redis-home].
10
-
11
- [redis-home]: http://redis.io
12
-
13
- A Ruby client that tries to match Redis' API one-to-one, while still
14
- providing an idiomatic interface. It features thread-safety, client-side
15
- sharding, pipelining, and an obsession for performance.
16
-
17
- ## Upgrading from 2.x to 3.0
18
-
19
- Please refer to the [CHANGELOG][changelog-3.0.0] for a summary of the
20
- most important changes, as well as a full list of changes.
21
-
22
- [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.
23
7
 
24
8
  ## Getting started
25
9
 
26
- To install **redis-rb**, run the following command:
10
+ Install with:
27
11
 
28
12
  ```
29
- gem install redis
13
+ $ gem install redis
30
14
  ```
31
15
 
32
- Or if you are using **bundler**, add
33
-
34
- ```
35
- gem 'redis', '~>3.2'
36
- ```
37
-
38
- to your `Gemfile`, and run `bundle install`
39
-
40
- As of version 2.0 this client only targets Redis version 2.0 and higher.
41
- You can use an older version of this client if you need to interface
42
- with a Redis instance older than 2.0, but this is no longer supported.
43
-
44
16
  You can connect to Redis by instantiating the `Redis` class:
45
17
 
46
18
  ```ruby
@@ -54,16 +26,17 @@ listening on `localhost`, port 6379. If you need to connect to a remote
54
26
  server or a different port, try:
55
27
 
56
28
  ```ruby
57
- redis = Redis.new(:host => "10.0.1.1", :port => 6380, :db => 15)
29
+ redis = Redis.new(host: "10.0.1.1", port: 6380, db: 15)
58
30
  ```
59
31
 
60
32
  You can also specify connection options as a [`redis://` URL][redis-url]:
61
33
 
62
34
  ```ruby
63
- redis = Redis.new(:url => "redis://:p4ssw0rd@10.0.1.1:6380/15")
35
+ redis = Redis.new(url: "redis://:p4ssw0rd@10.0.1.1:6380/15")
64
36
  ```
65
37
 
66
- [redis-url]: http://www.iana.org/assignments/uri-schemes/prov/redis
38
+ The client expects passwords with special chracters to be URL-encoded (i.e.
39
+ `CGI.escape(password)`).
67
40
 
68
41
  By default, the client will try to read the `REDIS_URL` environment variable
69
42
  and use that as URL to connect to. The above statement is therefore equivalent
@@ -72,13 +45,19 @@ to setting this environment variable and calling `Redis.new` without arguments.
72
45
  To connect to Redis listening on a Unix socket, try:
73
46
 
74
47
  ```ruby
75
- redis = Redis.new(:path => "/tmp/redis.sock")
48
+ redis = Redis.new(path: "/tmp/redis.sock")
76
49
  ```
77
50
 
78
51
  To connect to a password protected Redis instance, use:
79
52
 
80
53
  ```ruby
81
- redis = Redis.new(:password => "mysecret")
54
+ redis = Redis.new(password: "mysecret")
55
+ ```
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')
82
61
  ```
83
62
 
84
63
  The Redis class exports methods that are named identical to the commands
@@ -86,8 +65,6 @@ they execute. The arguments these methods accept are often identical to
86
65
  the arguments specified on the [Redis website][redis-commands]. For
87
66
  instance, the `SET` and `GET` commands can be called like this:
88
67
 
89
- [redis-commands]: http://redis.io/commands
90
-
91
68
  ```ruby
92
69
  redis.set("mykey", "hello world")
93
70
  # => "OK"
@@ -96,24 +73,22 @@ redis.get("mykey")
96
73
  # => "hello world"
97
74
  ```
98
75
 
99
- All commands, their arguments and return values are documented, and
100
- available on [rdoc.info][rdoc].
101
-
102
- [rdoc]: http://rdoc.info/github/redis/redis-rb/
76
+ All commands, their arguments, and return values are documented and
77
+ available on [RubyDoc.info][rubydoc].
103
78
 
104
79
  ## Sentinel support
105
80
 
106
- The client is able to perform automatic failovers by using [Redis
81
+ The client is able to perform automatic failover by using [Redis
107
82
  Sentinel](http://redis.io/topics/sentinel). Make sure to run Redis 2.8+
108
83
  if you want to use this feature.
109
84
 
110
85
  To connect using Sentinel, use:
111
86
 
112
87
  ```ruby
113
- SENTINELS = [{:host => "127.0.0.1", :port => 26380},
114
- {:host => "127.0.0.1", :port => 26381}]
88
+ SENTINELS = [{ host: "127.0.0.1", port: 26380 },
89
+ { host: "127.0.0.1", port: 26381 }]
115
90
 
116
- redis = Redis.new(:url => "redis://mymaster", :sentinels => SENTINELS, :role => :master)
91
+ redis = Redis.new(url: "redis://mymaster", sentinels: SENTINELS, role: :master)
117
92
  ```
118
93
 
119
94
  * The master name identifies a group of Redis instances composed of a master
@@ -130,10 +105,60 @@ but a few so that if one is down the client will try the next one. The client
130
105
  is able to remember the last Sentinel that was able to reply correctly and will
131
106
  use it for the next requests.
132
107
 
108
+ 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.
109
+
110
+ ```ruby
111
+ SENTINELS = [{ host: '127.0.0.1', port: 26380, password: 'mysecret' },
112
+ { host: '127.0.0.1', port: 26381, password: 'mysecret' }]
113
+
114
+ redis = Redis.new(host: 'mymaster', sentinels: SENTINELS, role: :master)
115
+ ```
116
+
117
+ ## Cluster support
118
+
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
+
133
158
  ## Storing objects
134
159
 
135
- Redis only stores strings as values. If you want to store an object, you
136
- can use a serialization mechanism such as JSON:
160
+ Redis "string" types can be used to store serialized Ruby objects, for
161
+ example with JSON:
137
162
 
138
163
  ```ruby
139
164
  require "json"
@@ -211,7 +236,7 @@ it can't connect to the server a `Redis::CannotConnectError` error will be raise
211
236
  ```ruby
212
237
  begin
213
238
  redis.ping
214
- rescue Exception => e
239
+ rescue StandardError => e
215
240
  e.inspect
216
241
  # => #<Redis::CannotConnectError: Timed out connecting to Redis on 10.0.1.1:6380>
217
242
 
@@ -222,6 +247,132 @@ end
222
247
 
223
248
  See lib/redis/errors.rb for information about what exceptions are possible.
224
249
 
250
+ ## Timeouts
251
+
252
+ The client allows you to configure connect, read, and write timeouts.
253
+ Passing a single `timeout` option will set all three values:
254
+
255
+ ```ruby
256
+ Redis.new(:timeout => 1)
257
+ ```
258
+
259
+ But you can use specific values for each of them:
260
+
261
+ ```ruby
262
+ Redis.new(
263
+ :connect_timeout => 0.2,
264
+ :read_timeout => 1.0,
265
+ :write_timeout => 0.5
266
+ )
267
+ ```
268
+
269
+ All timeout values are specified in seconds.
270
+
271
+ When using pub/sub, you can subscribe to a channel using a timeout as well:
272
+
273
+ ```ruby
274
+ redis = Redis.new(reconnect_attempts: 0)
275
+ redis.subscribe_with_timeout(5, "news") do |on|
276
+ on.message do |channel, message|
277
+ # ...
278
+ end
279
+ end
280
+ ```
281
+
282
+ If no message is received after 5 seconds, the client will unsubscribe.
283
+
284
+ ## Reconnections
285
+
286
+ The client allows you to configure how many `reconnect_attempts` it should
287
+ complete before declaring a connection as failed. Furthermore, you may want
288
+ to control the maximum duration between reconnection attempts with
289
+ `reconnect_delay` and `reconnect_delay_max`.
290
+
291
+ ```ruby
292
+ Redis.new(
293
+ :reconnect_attempts => 10,
294
+ :reconnect_delay => 1.5,
295
+ :reconnect_delay_max => 10.0,
296
+ )
297
+ ```
298
+
299
+ The delay values are specified in seconds. With the above configuration, the
300
+ client would attempt 10 reconnections, exponentially increasing the duration
301
+ between each attempt but it never waits longer than `reconnect_delay_max`.
302
+
303
+ This is the retry algorithm:
304
+
305
+ ```ruby
306
+ attempt_wait_time = [(reconnect_delay * 2**(attempt-1)), reconnect_delay_max].min
307
+ ```
308
+
309
+ **By default**, this gem will only **retry a connection once** and then fail, but with the
310
+ above configuration the reconnection attempt would look like this:
311
+
312
+ #|Attempt wait time|Total wait time
313
+ :-:|:-:|:-:
314
+ 1|1.5s|1.5s
315
+ 2|3.0s|4.5s
316
+ 3|6.0s|10.5s
317
+ 4|10.0s|20.5s
318
+ 5|10.0s|30.5s
319
+ 6|10.0s|40.5s
320
+ 7|10.0s|50.5s
321
+ 8|10.0s|60.5s
322
+ 9|10.0s|70.5s
323
+ 10|10.0s|80.5s
324
+
325
+ So if the reconnection attempt #10 succeeds 70 seconds have elapsed trying
326
+ to reconnect, this is likely fine in long-running background processes, but if
327
+ you use Redis to drive your website you might want to have a lower
328
+ `reconnect_delay_max` or have less `reconnect_attempts`.
329
+
330
+ ## SSL/TLS Support
331
+
332
+ This library supports natively terminating client side SSL/TLS connections
333
+ when talking to Redis via a server-side proxy such as [stunnel], [hitch],
334
+ or [ghostunnel].
335
+
336
+ To enable SSL support, pass the `:ssl => true` option when configuring the
337
+ Redis client, or pass in `:url => "rediss://..."` (like HTTPS for Redis).
338
+ You will also need to pass in an `:ssl_params => { ... }` hash used to
339
+ configure the `OpenSSL::SSL::SSLContext` object used for the connection:
340
+
341
+ ```ruby
342
+ redis = Redis.new(
343
+ :url => "rediss://:p4ssw0rd@10.0.1.1:6381/15",
344
+ :ssl_params => {
345
+ :ca_file => "/path/to/ca.crt"
346
+ }
347
+ )
348
+ ```
349
+
350
+ The options given to `:ssl_params` are passed directly to the
351
+ `OpenSSL::SSL::SSLContext#set_params` method and can be any valid attribute
352
+ of the SSL context. Please see the [OpenSSL::SSL::SSLContext documentation]
353
+ for all of the available attributes.
354
+
355
+ Here is an example of passing in params that can be used for SSL client
356
+ certificate authentication (a.k.a. mutual TLS):
357
+
358
+ ```ruby
359
+ redis = Redis.new(
360
+ :url => "rediss://:p4ssw0rd@10.0.1.1:6381/15",
361
+ :ssl_params => {
362
+ :ca_file => "/path/to/ca.crt",
363
+ :cert => OpenSSL::X509::Certificate.new(File.read("client.crt")),
364
+ :key => OpenSSL::PKey::RSA.new(File.read("client.key"))
365
+ }
366
+ )
367
+ ```
368
+
369
+ [stunnel]: https://www.stunnel.org/
370
+ [hitch]: https://hitch-tls.org/
371
+ [ghostunnel]: https://github.com/square/ghostunnel
372
+ [OpenSSL::SSL::SSLContext documentation]: http://ruby-doc.org/stdlib-2.3.0/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html
373
+
374
+ *NOTE:* SSL is only supported by the default "Ruby" driver
375
+
225
376
 
226
377
  ## Expert-Mode Options
227
378
 
@@ -294,35 +445,31 @@ redis = Redis.new(:driver => :synchrony)
294
445
 
295
446
  ## Testing
296
447
 
297
- This library is tested using [Travis][travis-home], where it is tested
298
- against the following interpreters and drivers:
448
+ This library is tested against recent Ruby and Redis versions.
449
+ Check [Github Actions][gh-actions-link] for the exact versions supported.
450
+
451
+ ## See Also
299
452
 
300
- * MRI 1.8.7 (drivers: ruby, hiredis)
301
- * MRI 1.9.2 (drivers: ruby, hiredis, synchrony)
302
- * MRI 1.9.3 (drivers: ruby, hiredis, synchrony)
303
- * MRI 2.0.0 (drivers: ruby, hiredis, synchrony)
304
- * JRuby 1.7 (1.8 mode) (drivers: ruby)
305
- * JRuby 1.7 (1.9 mode) (drivers: ruby)
453
+ - [async-redis](https://github.com/socketry/async-redis) — An [async](https://github.com/socketry/async) compatible Redis client.
306
454
 
307
455
  ## Contributors
308
456
 
309
- (ordered chronologically with more than 5 commits, see `git shortlog -sn` for
310
- all contributors)
311
-
312
- * Ezra Zygmuntowicz
313
- * Taylor Weibley
314
- * Matthew Clark
315
- * Brian McKinney
316
- * Luca Guidi
317
- * Salvatore Sanfilippo
318
- * Chris Wanstrath
319
- * Damian Janowski
320
- * Michel Martens
321
- * Nick Quaranto
322
- * Pieter Noordhuis
323
- * Ilya Grigorik
457
+ Several people contributed to redis-rb, but we would like to especially
458
+ mention Ezra Zygmuntowicz. Ezra introduced the Ruby community to many
459
+ new cool technologies, like Redis. He wrote the first version of this
460
+ client and evangelized Redis in Rubyland. Thank you, Ezra.
324
461
 
325
462
  ## Contributing
326
463
 
327
464
  [Fork the project](https://github.com/redis/redis-rb) and send pull
328
- requests. You can also ask for help at `#redis-rb` on Freenode.
465
+ requests.
466
+
467
+
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