redis 4.7.0 → 4.8.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5236e71d674779c964e99ebf2eac29efe80339a93de6907acfcd230a5d312153
4
- data.tar.gz: 208b4bf708d70a570c354da2d5570972416cbe6007e1f8d99c31f3ef4958a342
3
+ metadata.gz: c93b88c9766f0ba965110f61ff1e5cb3adcf378a515a9cdb7c345ef56159f98a
4
+ data.tar.gz: 6fa82d53bef3b0be6a5d192a925dfbd1e7585e66a5313605e631a1cf8585bf95
5
5
  SHA512:
6
- metadata.gz: c9c6446c4b666435afcc66256a4387b0360da61cfbf941252d91561e893219d650a8cd1bf98e8a28825c258e543078e6d3b6e22cb790e2ac9ff42af915dd8ef0
7
- data.tar.gz: e6649016acce9f6fd2e1767840ac3c07f5fc825576e5c304b4f1cb0b7a2e1c8ce8043450de75a1c910098a47f5bf53230b4efd74b7590b17f5022b04f0e23583
6
+ metadata.gz: 1d2b5d59615cfdc2ec756c16560b88d3f968193d7ac1c827574b775b202f3f63b9d3ab9748c89cae5d82471063a1aded9f82557b86f850b0a58a180d404ee15c
7
+ data.tar.gz: 866c1968b84397450ca8882175240c345bf2dfb3a88fa4579d78c7ce8ee581226a0eb6007ac6de638dfc654eca15bf045e6f1860c187e5d736b196cac8b721c9
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Unreleased
2
2
 
3
+ # 4.8.0
4
+
5
+ * Introduce `sadd?` and `srem?` as boolean returning versions of `sadd` and `srem`.
6
+ * Deprecate `sadd` and `srem` returning a boolean when called with a single argument.
7
+ To enable the redis 5.0 behavior you can set `Redis.sadd_returns_boolean = true`.
8
+ * Deprecate passing `timeout` as a positional argument in blocking commands (`brpop`, `blop`, etc).
9
+
10
+ # 4.7.1
11
+
12
+ * Gracefully handle OpenSSL 3.0 EOF Errors (`OpenSSL::SSL::SSLError: SSL_read: unexpected eof while reading`). See #1106
13
+ This happens frequently on heroku-22.
14
+
3
15
  # 4.7.0
4
16
 
5
17
  * Support single endpoint architecture with SSL/TLS in cluster mode. See #1086.
data/lib/redis/client.rb CHANGED
@@ -302,7 +302,7 @@ class Redis
302
302
  e2 = TimeoutError.new("Connection timed out")
303
303
  e2.set_backtrace(e1.backtrace)
304
304
  raise e2
305
- rescue Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED, Errno::EBADF, Errno::EINVAL => e
305
+ rescue Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED, Errno::EBADF, Errno::EINVAL, EOFError => e
306
306
  raise ConnectionError, "Connection lost (%s)" % [e.class.name.split("::").last]
307
307
  end
308
308
 
@@ -69,18 +69,40 @@ class Redis
69
69
  #
70
70
  # @param [String] key
71
71
  # @param [Integer] seconds time to live
72
+ # @param [Hash] options
73
+ # - `:nx => true`: Set expiry only when the key has no expiry.
74
+ # - `:xx => true`: Set expiry only when the key has an existing expiry.
75
+ # - `:gt => true`: Set expiry only when the new expiry is greater than current one.
76
+ # - `:lt => true`: Set expiry only when the new expiry is less than current one.
72
77
  # @return [Boolean] whether the timeout was set or not
73
- def expire(key, seconds)
74
- send_command([:expire, key, seconds], &Boolify)
78
+ def expire(key, seconds, nx: nil, xx: nil, gt: nil, lt: nil)
79
+ args = [:expire, key, seconds]
80
+ args << "NX" if nx
81
+ args << "XX" if xx
82
+ args << "GT" if gt
83
+ args << "LT" if lt
84
+
85
+ send_command(args, &Boolify)
75
86
  end
76
87
 
77
88
  # Set the expiration for a key as a UNIX timestamp.
78
89
  #
79
90
  # @param [String] key
80
91
  # @param [Integer] unix_time expiry time specified as a UNIX timestamp
92
+ # @param [Hash] options
93
+ # - `:nx => true`: Set expiry only when the key has no expiry.
94
+ # - `:xx => true`: Set expiry only when the key has an existing expiry.
95
+ # - `:gt => true`: Set expiry only when the new expiry is greater than current one.
96
+ # - `:lt => true`: Set expiry only when the new expiry is less than current one.
81
97
  # @return [Boolean] whether the timeout was set or not
82
- def expireat(key, unix_time)
83
- send_command([:expireat, key, unix_time], &Boolify)
98
+ def expireat(key, unix_time, nx: nil, xx: nil, gt: nil, lt: nil)
99
+ args = [:expireat, key, unix_time]
100
+ args << "NX" if nx
101
+ args << "XX" if xx
102
+ args << "GT" if gt
103
+ args << "LT" if lt
104
+
105
+ send_command(args, &Boolify)
84
106
  end
85
107
 
86
108
  # Get the time to live (in seconds) for a key.
@@ -103,18 +125,40 @@ class Redis
103
125
  #
104
126
  # @param [String] key
105
127
  # @param [Integer] milliseconds time to live
128
+ # @param [Hash] options
129
+ # - `:nx => true`: Set expiry only when the key has no expiry.
130
+ # - `:xx => true`: Set expiry only when the key has an existing expiry.
131
+ # - `:gt => true`: Set expiry only when the new expiry is greater than current one.
132
+ # - `:lt => true`: Set expiry only when the new expiry is less than current one.
106
133
  # @return [Boolean] whether the timeout was set or not
107
- def pexpire(key, milliseconds)
108
- send_command([:pexpire, key, milliseconds], &Boolify)
134
+ def pexpire(key, milliseconds, nx: nil, xx: nil, gt: nil, lt: nil)
135
+ args = [:pexpire, key, milliseconds]
136
+ args << "NX" if nx
137
+ args << "XX" if xx
138
+ args << "GT" if gt
139
+ args << "LT" if lt
140
+
141
+ send_command(args, &Boolify)
109
142
  end
110
143
 
111
144
  # Set the expiration for a key as number of milliseconds from UNIX Epoch.
112
145
  #
113
146
  # @param [String] key
114
147
  # @param [Integer] ms_unix_time expiry time specified as number of milliseconds from UNIX Epoch.
148
+ # @param [Hash] options
149
+ # - `:nx => true`: Set expiry only when the key has no expiry.
150
+ # - `:xx => true`: Set expiry only when the key has an existing expiry.
151
+ # - `:gt => true`: Set expiry only when the new expiry is greater than current one.
152
+ # - `:lt => true`: Set expiry only when the new expiry is less than current one.
115
153
  # @return [Boolean] whether the timeout was set or not
116
- def pexpireat(key, ms_unix_time)
117
- send_command([:pexpireat, key, ms_unix_time], &Boolify)
154
+ def pexpireat(key, ms_unix_time, nx: nil, xx: nil, gt: nil, lt: nil)
155
+ args = [:pexpireat, key, ms_unix_time]
156
+ args << "NX" if nx
157
+ args << "XX" if xx
158
+ args << "GT" if gt
159
+ args << "LT" if lt
160
+
161
+ send_command(args, &Boolify)
118
162
  end
119
163
 
120
164
  # Get the time to live (in milliseconds) for a key.
@@ -254,16 +254,17 @@ class Redis
254
254
  options = args.pop
255
255
  options[:timeout]
256
256
  elsif args.last.respond_to?(:to_int)
257
- # Issue deprecation notice in obnoxious mode...
258
- args.pop.to_int
257
+ last_arg = args.pop
258
+ ::Redis.deprecate!(
259
+ "Passing the timeout as a positional argument is deprecated, it should be passed as a keyword argument:\n" \
260
+ " redis.#{cmd}(#{args.map(&:inspect).join(', ')}, timeout: #{last_arg.to_int})" \
261
+ "(called from: #{caller(2, 1).first})"
262
+ )
263
+ last_arg.to_int
259
264
  end
260
265
 
261
266
  timeout ||= 0
262
267
 
263
- if args.size > 1
264
- # Issue deprecation notice in obnoxious mode...
265
- end
266
-
267
268
  keys = args.flatten
268
269
 
269
270
  command = [cmd, keys, timeout]
@@ -20,15 +20,23 @@ class Redis
20
20
  # array of members is specified, holding the number of members that were
21
21
  # successfully added
22
22
  def sadd(key, member)
23
- send_command([:sadd, key, member]) do |reply|
24
- if member.is_a? Array
25
- # Variadic: return integer
26
- reply
27
- else
28
- # Single argument: return boolean
29
- Boolify.call(reply)
30
- end
23
+ block = if Redis.sadd_returns_boolean && !member.is_a?(Array)
24
+ ::Redis.deprecate!(
25
+ "Redis#sadd will always return an Integer in Redis 5.0.0. Use Redis#sadd? instead." \
26
+ "(called from: #{caller(1, 1).first})"
27
+ )
28
+ Boolify
31
29
  end
30
+ send_command([:sadd, key, member], &block)
31
+ end
32
+
33
+ # Add one or more members to a set.
34
+ #
35
+ # @param [String] key
36
+ # @param [String, Array<String>] member one member, or array of members
37
+ # @return [Boolean] Whether or not at least one member was added.
38
+ def sadd?(key, member)
39
+ send_command([:sadd, key, member], &Boolify)
32
40
  end
33
41
 
34
42
  # Remove one or more members from a set.
@@ -40,15 +48,23 @@ class Redis
40
48
  # array of members is specified, holding the number of members that were
41
49
  # successfully removed
42
50
  def srem(key, member)
43
- send_command([:srem, key, member]) do |reply|
44
- if member.is_a? Array
45
- # Variadic: return integer
46
- reply
47
- else
48
- # Single argument: return boolean
49
- Boolify.call(reply)
50
- end
51
+ block = if Redis.sadd_returns_boolean && !member.is_a?(Array)
52
+ ::Redis.deprecate!(
53
+ "Redis#sadd will always return an Integer in Redis 5.0.0. Use Redis#sadd? instead." \
54
+ "(called from: #{caller(1, 1).first})"
55
+ )
56
+ Boolify
51
57
  end
58
+ send_command([:srem, key, member], &block)
59
+ end
60
+
61
+ # Remove one or more members from a set.
62
+ #
63
+ # @param [String] key
64
+ # @param [String, Array<String>] member one member, or array of members
65
+ # @return [Boolean] `Boolean` Whether or not a member was removed.
66
+ def srem?(key, member)
67
+ send_command([:srem, key, member], &Boolify)
52
68
  end
53
69
 
54
70
  # Remove and return one or more random member from a set.
@@ -41,10 +41,8 @@ class Redis
41
41
  # returning false.
42
42
  Boolify = lambda { |value|
43
43
  case value
44
- when 1
45
- true
46
- when 0
47
- false
44
+ when Integer
45
+ value > 0
48
46
  else
49
47
  value
50
48
  end
@@ -15,6 +15,8 @@ class Redis
15
15
 
16
16
  if config[:scheme] == "unix"
17
17
  connection.connect_unix(config[:path], connect_timeout)
18
+ elsif config[:scheme] == "rediss" || config[:ssl]
19
+ raise NotImplementedError, "SSL not supported by hiredis driver"
18
20
  else
19
21
  connection.connect(config[:host], config[:port], connect_timeout)
20
22
  end
@@ -384,6 +384,12 @@ class Redis
384
384
  format_reply(reply_type, line)
385
385
  rescue Errno::EAGAIN
386
386
  raise TimeoutError
387
+ rescue OpenSSL::SSL::SSLError => ssl_error
388
+ if ssl_error.message.match?(/SSL_read: unexpected eof while reading/i)
389
+ raise EOFError, ssl_error.message
390
+ else
391
+ raise
392
+ end
387
393
  end
388
394
 
389
395
  def format_reply(reply_type, line)
@@ -115,13 +115,13 @@ class Redis
115
115
  end
116
116
 
117
117
  # Set a key's time to live in seconds.
118
- def expire(key, seconds)
119
- node_for(key).expire(key, seconds)
118
+ def expire(key, seconds, **kwargs)
119
+ node_for(key).expire(key, seconds, **kwargs)
120
120
  end
121
121
 
122
122
  # Set the expiration for a key as a UNIX timestamp.
123
- def expireat(key, unix_time)
124
- node_for(key).expireat(key, unix_time)
123
+ def expireat(key, unix_time, **kwargs)
124
+ node_for(key).expireat(key, unix_time, **kwargs)
125
125
  end
126
126
 
127
127
  # Get the time to live (in seconds) for a key.
@@ -130,13 +130,13 @@ class Redis
130
130
  end
131
131
 
132
132
  # Set a key's time to live in milliseconds.
133
- def pexpire(key, milliseconds)
134
- node_for(key).pexpire(key, milliseconds)
133
+ def pexpire(key, milliseconds, **kwarg)
134
+ node_for(key).pexpire(key, milliseconds, **kwarg)
135
135
  end
136
136
 
137
137
  # Set the expiration for a key as number of milliseconds from UNIX Epoch.
138
- def pexpireat(key, ms_unix_time)
139
- node_for(key).pexpireat(key, ms_unix_time)
138
+ def pexpireat(key, ms_unix_time, **kwarg)
139
+ node_for(key).pexpireat(key, ms_unix_time, **kwarg)
140
140
  end
141
141
 
142
142
  # Get the time to live (in milliseconds) for a key.
@@ -464,12 +464,13 @@ class Redis
464
464
  options = args.pop
465
465
  options[:timeout]
466
466
  elsif args.last.respond_to?(:to_int)
467
- # Issue deprecation notice in obnoxious mode...
468
- args.pop.to_int
469
- end
470
-
471
- if args.size > 1
472
- # Issue deprecation notice in obnoxious mode...
467
+ last_arg = args.pop
468
+ ::Redis.deprecate!(
469
+ "Passing the timeout as a positional argument is deprecated, it should be passed as a keyword argument:\n" \
470
+ " redis.#{cmd}(#{args.map(&:inspect).join(', ')}, timeout: #{last_arg.to_int})" \
471
+ "(called from: #{caller(2, 1).first})"
472
+ )
473
+ last_arg.to_int
473
474
  end
474
475
 
475
476
  keys = args.flatten
@@ -543,11 +544,21 @@ class Redis
543
544
  node_for(key).sadd(key, member)
544
545
  end
545
546
 
547
+ # Add one or more members to a set.
548
+ def sadd?(key, member)
549
+ node_for(key).sadd?(key, member)
550
+ end
551
+
546
552
  # Remove one or more members from a set.
547
553
  def srem(key, member)
548
554
  node_for(key).srem(key, member)
549
555
  end
550
556
 
557
+ # Remove one or more members from a set.
558
+ def srem?(key, member)
559
+ node_for(key).srem?(key, member)
560
+ end
561
+
551
562
  # Remove and return a random member from a set.
552
563
  def spop(key, count = nil)
553
564
  node_for(key).spop(key, count)
data/lib/redis/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Redis
4
- VERSION = '4.7.0'
4
+ VERSION = '4.8.0'
5
5
  end
data/lib/redis.rb CHANGED
@@ -7,12 +7,13 @@ require "redis/commands"
7
7
  class Redis
8
8
  BASE_PATH = __dir__
9
9
  @exists_returns_integer = true
10
+ @sadd_returns_boolean = true
10
11
 
11
12
  Deprecated = Class.new(StandardError)
12
13
 
13
14
  class << self
14
15
  attr_reader :exists_returns_integer
15
- attr_accessor :silence_deprecations, :raise_deprecations
16
+ attr_accessor :silence_deprecations, :raise_deprecations, :sadd_returns_boolean
16
17
 
17
18
  def exists_returns_integer=(value)
18
19
  unless value
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.7.0
4
+ version: 4.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ezra Zygmuntowicz
@@ -16,7 +16,7 @@ authors:
16
16
  autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
- date: 2022-06-24 00:00:00.000000000 Z
19
+ date: 2022-08-22 00:00:00.000000000 Z
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  name: em-synchrony
@@ -119,9 +119,9 @@ licenses:
119
119
  metadata:
120
120
  bug_tracker_uri: https://github.com/redis/redis-rb/issues
121
121
  changelog_uri: https://github.com/redis/redis-rb/blob/master/CHANGELOG.md
122
- documentation_uri: https://www.rubydoc.info/gems/redis/4.7.0
122
+ documentation_uri: https://www.rubydoc.info/gems/redis/4.8.0
123
123
  homepage_uri: https://github.com/redis/redis-rb
124
- source_code_uri: https://github.com/redis/redis-rb/tree/v4.7.0
124
+ source_code_uri: https://github.com/redis/redis-rb/tree/v4.8.0
125
125
  post_install_message:
126
126
  rdoc_options: []
127
127
  require_paths: