redis 3.2.0 → 4.6.0

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 (133) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +278 -15
  3. data/README.md +260 -76
  4. data/lib/redis/client.rb +239 -115
  5. data/lib/redis/cluster/command.rb +79 -0
  6. data/lib/redis/cluster/command_loader.rb +33 -0
  7. data/lib/redis/cluster/key_slot_converter.rb +72 -0
  8. data/lib/redis/cluster/node.rb +120 -0
  9. data/lib/redis/cluster/node_key.rb +31 -0
  10. data/lib/redis/cluster/node_loader.rb +37 -0
  11. data/lib/redis/cluster/option.rb +93 -0
  12. data/lib/redis/cluster/slot.rb +86 -0
  13. data/lib/redis/cluster/slot_loader.rb +49 -0
  14. data/lib/redis/cluster.rb +315 -0
  15. data/lib/redis/commands/bitmaps.rb +63 -0
  16. data/lib/redis/commands/cluster.rb +45 -0
  17. data/lib/redis/commands/connection.rb +58 -0
  18. data/lib/redis/commands/geo.rb +84 -0
  19. data/lib/redis/commands/hashes.rb +251 -0
  20. data/lib/redis/commands/hyper_log_log.rb +37 -0
  21. data/lib/redis/commands/keys.rb +411 -0
  22. data/lib/redis/commands/lists.rb +289 -0
  23. data/lib/redis/commands/pubsub.rb +72 -0
  24. data/lib/redis/commands/scripting.rb +114 -0
  25. data/lib/redis/commands/server.rb +188 -0
  26. data/lib/redis/commands/sets.rb +207 -0
  27. data/lib/redis/commands/sorted_sets.rb +804 -0
  28. data/lib/redis/commands/streams.rb +382 -0
  29. data/lib/redis/commands/strings.rb +313 -0
  30. data/lib/redis/commands/transactions.rb +92 -0
  31. data/lib/redis/commands.rb +242 -0
  32. data/lib/redis/connection/command_helper.rb +7 -10
  33. data/lib/redis/connection/hiredis.rb +11 -6
  34. data/lib/redis/connection/registry.rb +2 -1
  35. data/lib/redis/connection/ruby.rb +173 -64
  36. data/lib/redis/connection/synchrony.rb +32 -8
  37. data/lib/redis/connection.rb +3 -1
  38. data/lib/redis/distributed.rb +233 -74
  39. data/lib/redis/errors.rb +48 -0
  40. data/lib/redis/hash_ring.rb +30 -72
  41. data/lib/redis/pipeline.rb +145 -12
  42. data/lib/redis/subscribe.rb +20 -13
  43. data/lib/redis/version.rb +3 -1
  44. data/lib/redis.rb +171 -2476
  45. metadata +71 -165
  46. data/.gitignore +0 -15
  47. data/.travis/Gemfile +0 -11
  48. data/.travis.yml +0 -54
  49. data/.yardopts +0 -3
  50. data/Gemfile +0 -4
  51. data/Rakefile +0 -68
  52. data/benchmarking/logging.rb +0 -71
  53. data/benchmarking/pipeline.rb +0 -51
  54. data/benchmarking/speed.rb +0 -21
  55. data/benchmarking/suite.rb +0 -24
  56. data/benchmarking/worker.rb +0 -71
  57. data/examples/basic.rb +0 -15
  58. data/examples/consistency.rb +0 -114
  59. data/examples/dist_redis.rb +0 -43
  60. data/examples/incr-decr.rb +0 -17
  61. data/examples/list.rb +0 -26
  62. data/examples/pubsub.rb +0 -37
  63. data/examples/sentinel/sentinel.conf +0 -9
  64. data/examples/sentinel/start +0 -49
  65. data/examples/sentinel.rb +0 -41
  66. data/examples/sets.rb +0 -36
  67. data/examples/unicorn/config.ru +0 -3
  68. data/examples/unicorn/unicorn.rb +0 -20
  69. data/redis.gemspec +0 -43
  70. data/test/bitpos_test.rb +0 -69
  71. data/test/blocking_commands_test.rb +0 -42
  72. data/test/command_map_test.rb +0 -30
  73. data/test/commands_on_hashes_test.rb +0 -21
  74. data/test/commands_on_hyper_log_log_test.rb +0 -21
  75. data/test/commands_on_lists_test.rb +0 -20
  76. data/test/commands_on_sets_test.rb +0 -77
  77. data/test/commands_on_sorted_sets_test.rb +0 -123
  78. data/test/commands_on_strings_test.rb +0 -101
  79. data/test/commands_on_value_types_test.rb +0 -131
  80. data/test/connection_handling_test.rb +0 -189
  81. data/test/db/.gitkeep +0 -0
  82. data/test/distributed_blocking_commands_test.rb +0 -46
  83. data/test/distributed_commands_on_hashes_test.rb +0 -10
  84. data/test/distributed_commands_on_hyper_log_log_test.rb +0 -33
  85. data/test/distributed_commands_on_lists_test.rb +0 -22
  86. data/test/distributed_commands_on_sets_test.rb +0 -83
  87. data/test/distributed_commands_on_sorted_sets_test.rb +0 -18
  88. data/test/distributed_commands_on_strings_test.rb +0 -59
  89. data/test/distributed_commands_on_value_types_test.rb +0 -95
  90. data/test/distributed_commands_requiring_clustering_test.rb +0 -164
  91. data/test/distributed_connection_handling_test.rb +0 -23
  92. data/test/distributed_internals_test.rb +0 -70
  93. data/test/distributed_key_tags_test.rb +0 -52
  94. data/test/distributed_persistence_control_commands_test.rb +0 -26
  95. data/test/distributed_publish_subscribe_test.rb +0 -92
  96. data/test/distributed_remote_server_control_commands_test.rb +0 -66
  97. data/test/distributed_scripting_test.rb +0 -102
  98. data/test/distributed_sorting_test.rb +0 -20
  99. data/test/distributed_test.rb +0 -58
  100. data/test/distributed_transactions_test.rb +0 -32
  101. data/test/encoding_test.rb +0 -18
  102. data/test/error_replies_test.rb +0 -59
  103. data/test/fork_safety_test.rb +0 -65
  104. data/test/helper.rb +0 -232
  105. data/test/helper_test.rb +0 -24
  106. data/test/internals_test.rb +0 -434
  107. data/test/lint/blocking_commands.rb +0 -150
  108. data/test/lint/hashes.rb +0 -162
  109. data/test/lint/hyper_log_log.rb +0 -60
  110. data/test/lint/lists.rb +0 -143
  111. data/test/lint/sets.rb +0 -125
  112. data/test/lint/sorted_sets.rb +0 -238
  113. data/test/lint/strings.rb +0 -260
  114. data/test/lint/value_types.rb +0 -122
  115. data/test/persistence_control_commands_test.rb +0 -26
  116. data/test/pipelining_commands_test.rb +0 -242
  117. data/test/publish_subscribe_test.rb +0 -210
  118. data/test/remote_server_control_commands_test.rb +0 -117
  119. data/test/scanning_test.rb +0 -413
  120. data/test/scripting_test.rb +0 -78
  121. data/test/sorting_test.rb +0 -59
  122. data/test/support/connection/hiredis.rb +0 -1
  123. data/test/support/connection/ruby.rb +0 -1
  124. data/test/support/connection/synchrony.rb +0 -17
  125. data/test/support/redis_mock.rb +0 -115
  126. data/test/support/wire/synchrony.rb +0 -24
  127. data/test/support/wire/thread.rb +0 -5
  128. data/test/synchrony_driver.rb +0 -88
  129. data/test/test.conf +0 -9
  130. data/test/thread_safety_test.rb +0 -32
  131. data/test/transactions_test.rb +0 -264
  132. data/test/unknown_commands_test.rb +0 -14
  133. data/test/url_param_test.rb +0 -132
@@ -1,63 +1,101 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "redis/connection/registry"
2
4
  require "redis/connection/command_helper"
3
5
  require "redis/errors"
6
+
4
7
  require "socket"
8
+ require "timeout"
9
+
10
+ begin
11
+ require "openssl"
12
+ rescue LoadError
13
+ # Not all systems have OpenSSL support
14
+ end
5
15
 
6
16
  class Redis
7
17
  module Connection
8
18
  module SocketMixin
9
-
10
- CRLF = "\r\n".freeze
19
+ CRLF = "\r\n"
11
20
 
12
21
  def initialize(*args)
13
22
  super(*args)
14
23
 
15
- @timeout = nil
16
- @buffer = ""
24
+ @timeout = @write_timeout = nil
25
+ @buffer = "".b
17
26
  end
18
27
 
19
28
  def timeout=(timeout)
20
- if timeout && timeout > 0
21
- @timeout = timeout
22
- else
23
- @timeout = nil
24
- end
29
+ @timeout = (timeout if timeout && timeout > 0)
30
+ end
31
+
32
+ def write_timeout=(timeout)
33
+ @write_timeout = (timeout if timeout && timeout > 0)
25
34
  end
26
35
 
27
36
  def read(nbytes)
28
37
  result = @buffer.slice!(0, nbytes)
29
38
 
30
- while result.bytesize < nbytes
31
- result << _read_from_socket(nbytes - result.bytesize)
32
- end
39
+ buffer = String.new(capacity: nbytes, encoding: Encoding::ASCII_8BIT)
40
+ result << _read_from_socket(nbytes - result.bytesize, buffer) while result.bytesize < nbytes
33
41
 
34
42
  result
35
43
  end
36
44
 
37
45
  def gets
38
- crlf = nil
39
-
40
- while (crlf = @buffer.index(CRLF)) == nil
41
- @buffer << _read_from_socket(1024)
46
+ while (crlf = @buffer.index(CRLF)).nil?
47
+ @buffer << _read_from_socket(16_384)
42
48
  end
43
49
 
44
50
  @buffer.slice!(0, crlf + CRLF.bytesize)
45
51
  end
46
52
 
47
- def _read_from_socket(nbytes)
48
- begin
49
- read_nonblock(nbytes)
50
-
51
- rescue Errno::EWOULDBLOCK, Errno::EAGAIN
52
- if IO.select([self], nil, nil, @timeout)
53
- retry
54
- else
55
- raise Redis::TimeoutError
53
+ def _read_from_socket(nbytes, buffer = nil)
54
+ loop do
55
+ case chunk = read_nonblock(nbytes, buffer, exception: false)
56
+ when :wait_readable
57
+ unless wait_readable(@timeout)
58
+ raise Redis::TimeoutError
59
+ end
60
+ when :wait_writable
61
+ unless wait_writable(@timeout)
62
+ raise Redis::TimeoutError
63
+ end
64
+ when nil
65
+ raise Errno::ECONNRESET
66
+ when String
67
+ return chunk
56
68
  end
57
69
  end
70
+ end
71
+
72
+ def write(buffer)
73
+ return super(buffer) unless @write_timeout
74
+
75
+ bytes_to_write = buffer.bytesize
76
+ total_bytes_written = 0
77
+ loop do
78
+ case bytes_written = write_nonblock(buffer, exception: false)
79
+ when :wait_readable
80
+ unless wait_readable(@write_timeout)
81
+ raise Redis::TimeoutError
82
+ end
83
+ when :wait_writable
84
+ unless wait_writable(@write_timeout)
85
+ raise Redis::TimeoutError
86
+ end
87
+ when nil
88
+ raise Errno::ECONNRESET
89
+ when Integer
90
+ total_bytes_written += bytes_written
91
+
92
+ if total_bytes_written >= bytes_to_write
93
+ return total_bytes_written
94
+ end
58
95
 
59
- rescue EOFError
60
- raise Errno::ECONNRESET
96
+ buffer = buffer.byteslice(bytes_written..-1)
97
+ end
98
+ end
61
99
  end
62
100
  end
63
101
 
@@ -66,7 +104,6 @@ class Redis
66
104
  require "timeout"
67
105
 
68
106
  class TCPSocket < ::TCPSocket
69
-
70
107
  include SocketMixin
71
108
 
72
109
  def self.connect(host, port, timeout)
@@ -82,7 +119,6 @@ class Redis
82
119
  if defined?(::UNIXSocket)
83
120
 
84
121
  class UNIXSocket < ::UNIXSocket
85
-
86
122
  include SocketMixin
87
123
 
88
124
  def self.connect(path, timeout)
@@ -94,13 +130,14 @@ class Redis
94
130
  raise TimeoutError
95
131
  end
96
132
 
97
- # JRuby raises Errno::EAGAIN on #read_nonblock even when IO.select
133
+ # JRuby raises Errno::EAGAIN on #read_nonblock even when it
98
134
  # says it is readable (1.6.6, in both 1.8 and 1.9 mode).
99
135
  # Use the blocking #readpartial method instead.
100
136
 
101
- def _read_from_socket(nbytes)
137
+ def _read_from_socket(nbytes, _buffer = nil)
138
+ # JRuby: Throw away the buffer as we won't need it
139
+ # but still need to support the max arity of 2
102
140
  readpartial(nbytes)
103
-
104
141
  rescue EOFError
105
142
  raise Errno::ECONNRESET
106
143
  end
@@ -111,19 +148,16 @@ class Redis
111
148
  else
112
149
 
113
150
  class TCPSocket < ::Socket
114
-
115
151
  include SocketMixin
116
152
 
117
- def self.connect_addrinfo(ai, port, timeout)
118
- sock = new(::Socket.const_get(ai[0]), Socket::SOCK_STREAM, 0)
119
- sockaddr = ::Socket.pack_sockaddr_in(port, ai[3])
153
+ def self.connect_addrinfo(addrinfo, port, timeout)
154
+ sock = new(::Socket.const_get(addrinfo[0]), Socket::SOCK_STREAM, 0)
155
+ sockaddr = ::Socket.pack_sockaddr_in(port, addrinfo[3])
120
156
 
121
157
  begin
122
158
  sock.connect_nonblock(sockaddr)
123
159
  rescue Errno::EINPROGRESS
124
- if IO.select(nil, [sock], nil, timeout) == nil
125
- raise TimeoutError
126
- end
160
+ raise TimeoutError unless sock.wait_writable(timeout)
127
161
 
128
162
  begin
129
163
  sock.connect_nonblock(sockaddr)
@@ -162,14 +196,13 @@ class Redis
162
196
  return connect_addrinfo(ai, port, timeout)
163
197
  rescue SystemCallError
164
198
  # Raise if this was our last attempt.
165
- raise if addrinfo.length == i+1
199
+ raise if addrinfo.length == i + 1
166
200
  end
167
201
  end
168
202
  end
169
203
  end
170
204
 
171
205
  class UNIXSocket < ::Socket
172
-
173
206
  include SocketMixin
174
207
 
175
208
  def self.connect(path, timeout)
@@ -179,9 +212,7 @@ class Redis
179
212
  begin
180
213
  sock.connect_nonblock(sockaddr)
181
214
  rescue Errno::EINPROGRESS
182
- if IO.select(nil, [sock], nil, timeout) == nil
183
- raise TimeoutError
184
- end
215
+ raise TimeoutError unless sock.wait_writable(timeout)
185
216
 
186
217
  begin
187
218
  sock.connect_nonblock(sockaddr)
@@ -195,29 +226,97 @@ class Redis
195
226
 
196
227
  end
197
228
 
229
+ if defined?(OpenSSL)
230
+ class SSLSocket < ::OpenSSL::SSL::SSLSocket
231
+ include SocketMixin
232
+
233
+ unless method_defined?(:wait_readable)
234
+ def wait_readable(timeout = nil)
235
+ to_io.wait_readable(timeout)
236
+ end
237
+ end
238
+
239
+ unless method_defined?(:wait_writable)
240
+ def wait_writable(timeout = nil)
241
+ to_io.wait_writable(timeout)
242
+ end
243
+ end
244
+
245
+ def self.connect(host, port, timeout, ssl_params)
246
+ # NOTE: this is using Redis::Connection::TCPSocket
247
+ tcp_sock = TCPSocket.connect(host, port, timeout)
248
+
249
+ ctx = OpenSSL::SSL::SSLContext.new
250
+
251
+ # The provided parameters are merged into OpenSSL::SSL::SSLContext::DEFAULT_PARAMS
252
+ ctx.set_params(ssl_params || {})
253
+
254
+ ssl_sock = new(tcp_sock, ctx)
255
+ ssl_sock.hostname = host
256
+
257
+ begin
258
+ # Initiate the socket connection in the background. If it doesn't fail
259
+ # immediately it will raise an IO::WaitWritable (Errno::EINPROGRESS)
260
+ # indicating the connection is in progress.
261
+ # Unlike waiting for a tcp socket to connect, you can't time out ssl socket
262
+ # connections during the connect phase properly, because IO.select only partially works.
263
+ # Instead, you have to retry.
264
+ ssl_sock.connect_nonblock
265
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable
266
+ if ssl_sock.wait_readable(timeout)
267
+ retry
268
+ else
269
+ raise TimeoutError
270
+ end
271
+ rescue IO::WaitWritable
272
+ if ssl_sock.wait_writable(timeout)
273
+ retry
274
+ else
275
+ raise TimeoutError
276
+ end
277
+ end
278
+
279
+ unless ctx.verify_mode == OpenSSL::SSL::VERIFY_NONE || (
280
+ ctx.respond_to?(:verify_hostname) &&
281
+ !ctx.verify_hostname
282
+ )
283
+ ssl_sock.post_connection_check(host)
284
+ end
285
+
286
+ ssl_sock
287
+ end
288
+ end
289
+ end
290
+
198
291
  class Ruby
199
292
  include Redis::Connection::CommandHelper
200
293
 
201
- MINUS = "-".freeze
202
- PLUS = "+".freeze
203
- COLON = ":".freeze
204
- DOLLAR = "$".freeze
205
- ASTERISK = "*".freeze
294
+ MINUS = "-"
295
+ PLUS = "+"
296
+ COLON = ":"
297
+ DOLLAR = "$"
298
+ ASTERISK = "*"
206
299
 
207
300
  def self.connect(config)
208
301
  if config[:scheme] == "unix"
209
- sock = UNIXSocket.connect(config[:path], config[:timeout])
302
+ raise ArgumentError, "SSL incompatible with unix sockets" if config[:ssl]
303
+
304
+ sock = UNIXSocket.connect(config[:path], config[:connect_timeout])
305
+ elsif config[:scheme] == "rediss" || config[:ssl]
306
+ sock = SSLSocket.connect(config[:host], config[:port], config[:connect_timeout], config[:ssl_params])
210
307
  else
211
- sock = TCPSocket.connect(config[:host], config[:port], config[:timeout])
308
+ sock = TCPSocket.connect(config[:host], config[:port], config[:connect_timeout])
212
309
  end
213
310
 
214
311
  instance = new(sock)
215
- instance.timeout = config[:timeout]
312
+ instance.timeout = config[:read_timeout]
313
+ instance.write_timeout = config[:write_timeout]
216
314
  instance.set_tcp_keepalive config[:tcp_keepalive]
315
+ instance.set_tcp_nodelay if sock.is_a? TCPSocket
217
316
  instance
218
317
  end
219
318
 
220
- if [:SOL_SOCKET, :SO_KEEPALIVE, :SOL_TCP, :TCP_KEEPIDLE, :TCP_KEEPINTVL, :TCP_KEEPCNT].all?{|c| Socket.const_defined? c}
319
+ if %i[SOL_SOCKET SO_KEEPALIVE SOL_TCP TCP_KEEPIDLE TCP_KEEPINTVL TCP_KEEPCNT].all? { |c| Socket.const_defined? c }
221
320
  def set_tcp_keepalive(keepalive)
222
321
  return unless keepalive.is_a?(Hash)
223
322
 
@@ -229,14 +328,13 @@ class Redis
229
328
 
230
329
  def get_tcp_keepalive
231
330
  {
232
- :time => @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPIDLE).int,
233
- :intvl => @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPINTVL).int,
234
- :probes => @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPCNT).int,
331
+ time: @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPIDLE).int,
332
+ intvl: @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPINTVL).int,
333
+ probes: @sock.getsockopt(Socket::SOL_TCP, Socket::TCP_KEEPCNT).int
235
334
  }
236
335
  end
237
336
  else
238
- def set_tcp_keepalive(keepalive)
239
- end
337
+ def set_tcp_keepalive(keepalive); end
240
338
 
241
339
  def get_tcp_keepalive
242
340
  {
@@ -244,12 +342,21 @@ class Redis
244
342
  end
245
343
  end
246
344
 
345
+ # disables Nagle's Algorithm, prevents multiple round trips with MULTI
346
+ if %i[IPPROTO_TCP TCP_NODELAY].all? { |c| Socket.const_defined? c }
347
+ def set_tcp_nodelay
348
+ @sock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
349
+ end
350
+ else
351
+ def set_tcp_nodelay; end
352
+ end
353
+
247
354
  def initialize(sock)
248
355
  @sock = sock
249
356
  end
250
357
 
251
358
  def connected?
252
- !! @sock
359
+ !!@sock
253
360
  end
254
361
 
255
362
  def disconnect
@@ -260,9 +367,11 @@ class Redis
260
367
  end
261
368
 
262
369
  def timeout=(timeout)
263
- if @sock.respond_to?(:timeout=)
264
- @sock.timeout = timeout
265
- end
370
+ @sock.timeout = timeout if @sock.respond_to?(:timeout=)
371
+ end
372
+
373
+ def write_timeout=(timeout)
374
+ @sock.write_timeout = timeout
266
375
  end
267
376
 
268
377
  def write(command)
@@ -273,7 +382,6 @@ class Redis
273
382
  line = @sock.gets
274
383
  reply_type = line.slice!(0, 1)
275
384
  format_reply(reply_type, line)
276
-
277
385
  rescue Errno::EAGAIN
278
386
  raise TimeoutError
279
387
  end
@@ -285,7 +393,7 @@ class Redis
285
393
  when COLON then format_integer_reply(line)
286
394
  when DOLLAR then format_bulk_reply(line)
287
395
  when ASTERISK then format_multi_bulk_reply(line)
288
- else raise ProtocolError.new(reply_type)
396
+ else raise ProtocolError, reply_type
289
397
  end
290
398
  end
291
399
 
@@ -304,6 +412,7 @@ class Redis
304
412
  def format_bulk_reply(line)
305
413
  bulklen = line.to_i
306
414
  return if bulklen == -1
415
+
307
416
  reply = encode(@sock.read(bulklen))
308
417
  @sock.read(2) # Discard CRLF.
309
418
  reply
@@ -1,14 +1,24 @@
1
- require "redis/connection/command_helper"
1
+ # frozen_string_literal: true
2
+
2
3
  require "redis/connection/registry"
4
+ require "redis/connection/command_helper"
3
5
  require "redis/errors"
6
+
4
7
  require "em-synchrony"
5
8
  require "hiredis/reader"
6
9
 
10
+ ::Redis.deprecate!(
11
+ "The redis synchrony driver is deprecated and will be removed in redis-rb 5.0.0. " \
12
+ "We're looking for people to maintain it as a separate gem, see https://github.com/redis/redis-rb/issues/915"
13
+ )
14
+
7
15
  class Redis
8
16
  module Connection
9
17
  class RedisClient < EventMachine::Connection
10
18
  include EventMachine::Deferrable
11
19
 
20
+ attr_accessor :timeout
21
+
12
22
  def post_init
13
23
  @req = nil
14
24
  @connected = false
@@ -44,6 +54,7 @@ class Redis
44
54
 
45
55
  def read
46
56
  @req = EventMachine::DefaultDeferrable.new
57
+ @req.timeout(@timeout, :timeout) if @timeout > 0
47
58
  EventMachine::Synchrony.sync @req
48
59
  end
49
60
 
@@ -67,10 +78,20 @@ class Redis
67
78
 
68
79
  def self.connect(config)
69
80
  if config[:scheme] == "unix"
70
- conn = EventMachine.connect_unix_domain(config[:path], RedisClient)
81
+ begin
82
+ conn = EventMachine.connect_unix_domain(config[:path], RedisClient)
83
+ rescue RuntimeError => e
84
+ if e.message == "no connection"
85
+ raise Errno::ECONNREFUSED
86
+ else
87
+ raise e
88
+ end
89
+ end
90
+ elsif config[:scheme] == "rediss" || config[:ssl]
91
+ raise NotImplementedError, "SSL not supported by synchrony driver"
71
92
  else
72
93
  conn = EventMachine.connect(config[:host], config[:port], RedisClient) do |c|
73
- c.pending_connect_timeout = [config[:timeout], 0.1].max
94
+ c.pending_connect_timeout = [config[:connect_timeout], 0.1].max
74
95
  end
75
96
  end
76
97
 
@@ -81,7 +102,7 @@ class Redis
81
102
  raise Errno::ECONNREFUSED if Fiber.yield == :refused
82
103
 
83
104
  instance = new(conn)
84
- instance.timeout = config[:timeout]
105
+ instance.timeout = config[:read_timeout]
85
106
  instance
86
107
  end
87
108
 
@@ -90,11 +111,11 @@ class Redis
90
111
  end
91
112
 
92
113
  def connected?
93
- @connection && @connection.connected?
114
+ @connection&.connected?
94
115
  end
95
116
 
96
117
  def timeout=(timeout)
97
- @timeout = timeout
118
+ @connection.timeout = timeout
98
119
  end
99
120
 
100
121
  def disconnect
@@ -109,10 +130,13 @@ class Redis
109
130
  def read
110
131
  type, payload = @connection.read
111
132
 
112
- if type == :reply
133
+ case type
134
+ when :reply
113
135
  payload
114
- elsif type == :error
136
+ when :error
115
137
  raise payload
138
+ when :timeout
139
+ raise TimeoutError
116
140
  else
117
141
  raise "Unknown type #{type.inspect}"
118
142
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "redis/connection/registry"
2
4
 
3
5
  # If a connection driver was required before this file, the array
@@ -6,4 +8,4 @@ require "redis/connection/registry"
6
8
  # the plain Ruby driver as our default. Another driver can be required at a
7
9
  # later point in time, causing it to be the last element of the #drivers array
8
10
  # and therefore be chosen by default.
9
- require "redis/connection/ruby" if Redis::Connection.drivers.empty?
11
+ require_relative "connection/ruby" if Redis::Connection.drivers.empty?