redis 5.0.7 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1dde5fad5c2d0c73c390528b059ab36b185dd61a2c32e4f9be9512bb4516977b
4
- data.tar.gz: cda581f3f9b0b4238f15b4b3ddf7566fb6ca02b60ee7951b903e8e195bd395cd
3
+ metadata.gz: ab20cee7f44b7d5f2736e1fbc7073cb950f52ceefc3dc1ff0edf9b4b778c7d8d
4
+ data.tar.gz: 76b0b6169311906b2ee634f9314c74052a1612245d7e33220aab5cb2c617af8a
5
5
  SHA512:
6
- metadata.gz: 122fd647eda1a251370f32dfefb4711411b0ff9b0e9185cdb871c389c99d5b80a80d554a6b7787ed10e515291b1ebed6dceb2364f8c28021ce6fdedd3297d08e
7
- data.tar.gz: 13aadc0709a9fc7779ad7ad1f64bb3d3b26da57eb44dd2ebd629d5ed2d34ea17c782337ce92e1047e7ae736df8b90eafb2e935e460f1b1af979621942dad772f
6
+ metadata.gz: 220927cf03b0ad6ab0c7340d9b32ed073e379974d054eba12cf966ad65837eba00f114d1fdeb166780ead645befcc3ee9fb3a83aab8e8cb0b1661370f401f8cb
7
+ data.tar.gz: 8f9476be4c7d4a3dd8dc1f29265b184932f67b49d524a0c79865dc95eee3ba165e9d24cb3f699ce287b886cc4f38b88574a5b33b1bab48f2fe9971597b7d2c5c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Unreleased
2
2
 
3
+ # 5.1.0
4
+
5
+ - `multi` now accept a `watch` keyword argument like `redis-client`. See #1236.
6
+ - `bitcount` and `bitpos` now accept a `scale:` argument on Redis 7+. See #1242
7
+ - Added `expiretime` and `pexpiretime`. See #1248.
8
+
9
+ # 5.0.8
10
+
11
+ - Fix `Redis#without_reconnect` for sentinel clients. Fix #1212.
12
+ - Add `sentinel_username`, `sentinel_password` for sentinel clients. Bump `redis-client` to `>=0.17.0`. See #1213
13
+
3
14
  # 5.0.7
4
15
 
5
16
  - Fix compatibility with `redis-client 0.15.0` when using Redis Sentinel. Fix #1209.
data/README.md CHANGED
@@ -120,19 +120,39 @@ but a few so that if one is down the client will try the next one. The client
120
120
  is able to remember the last Sentinel that was able to reply correctly and will
121
121
  use it for the next requests.
122
122
 
123
- 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.
123
+ To [authenticate](https://redis.io/docs/management/sentinel/#configuring-sentinel-instances-with-authentication) Sentinel itself, you can specify the `sentinel_username` and `sentinel_password`. Exclude the `sentinel_username` option if you're using password-only authentication.
124
124
 
125
125
  ```ruby
126
- SENTINELS = [{ host: '127.0.0.1', port: 26380, password: 'mysecret' },
127
- { host: '127.0.0.1', port: 26381, password: 'mysecret' }]
126
+ SENTINELS = [{ host: '127.0.0.1', port: 26380},
127
+ { host: '127.0.0.1', port: 26381}]
128
128
 
129
- redis = Redis.new(name: 'mymaster', sentinels: SENTINELS, role: :master)
129
+ redis = Redis.new(name: 'mymaster', sentinels: SENTINELS, sentinel_username: 'appuser', sentinel_password: 'mysecret', role: :master)
130
130
  ```
131
131
 
132
- Also the name can be passed as an url:
132
+ If you specify a username and/or password at the top level for your main Redis instance, Sentinel *will not* using thouse credentials
133
133
 
134
134
  ```ruby
135
- redis = Redis.new(name: "redis://mymaster", sentinels: SENTINELS, role: :master)
135
+ # Use 'mysecret' to authenticate against the mymaster instance, but skip authentication for the sentinels:
136
+ SENTINELS = [{ host: '127.0.0.1', port: 26380 },
137
+ { host: '127.0.0.1', port: 26381 }]
138
+
139
+ redis = Redis.new(name: 'mymaster', sentinels: SENTINELS, role: :master, password: 'mysecret')
140
+ ```
141
+
142
+ So you have to provide Sentinel credential and Redis explictly even they are the same
143
+
144
+ ```ruby
145
+ # Use 'mysecret' to authenticate against the mymaster instance and sentinel
146
+ SENTINELS = [{ host: '127.0.0.1', port: 26380 },
147
+ { host: '127.0.0.1', port: 26381 }]
148
+
149
+ redis = Redis.new(name: 'mymaster', sentinels: SENTINELS, role: :master, password: 'mysecret', sentinel_password: 'mysecret')
150
+ ```
151
+
152
+ Also the `name`, `password`, `username` and `db` for Redis instance can be passed as an url:
153
+
154
+ ```ruby
155
+ redis = Redis.new(url: "redis://appuser:mysecret@mymaster/10", sentinels: SENTINELS, role: :master)
136
156
  ```
137
157
 
138
158
  ## Cluster support
data/lib/redis/client.rb CHANGED
@@ -27,18 +27,18 @@ class Redis
27
27
  super(protocol: 2, **kwargs, client_implementation: ::RedisClient)
28
28
  end
29
29
 
30
- def translate_error!(error)
31
- redis_error = translate_error_class(error.class)
30
+ def translate_error!(error, mapping: ERROR_MAPPING)
31
+ redis_error = translate_error_class(error.class, mapping: mapping)
32
32
  raise redis_error, error.message, error.backtrace
33
33
  end
34
34
 
35
35
  private
36
36
 
37
- def translate_error_class(error_class)
38
- ERROR_MAPPING.fetch(error_class)
37
+ def translate_error_class(error_class, mapping: ERROR_MAPPING)
38
+ mapping.fetch(error_class)
39
39
  rescue IndexError
40
- if (client_error = error_class.ancestors.find { |a| ERROR_MAPPING[a] })
41
- ERROR_MAPPING[error_class] = ERROR_MAPPING[client_error]
40
+ if (client_error = error_class.ancestors.find { |a| mapping[a] })
41
+ mapping[error_class] = mapping[client_error]
42
42
  else
43
43
  raise
44
44
  end
@@ -111,16 +111,12 @@ class Redis
111
111
  Client.translate_error!(error)
112
112
  end
113
113
 
114
- def multi
114
+ def multi(watch: nil)
115
115
  super
116
116
  rescue ::RedisClient::Error => error
117
117
  Client.translate_error!(error)
118
118
  end
119
119
 
120
- def disable_reconnection(&block)
121
- ensure_connected(retryable: false, &block)
122
- end
123
-
124
120
  def inherit_socket!
125
121
  @inherit_socket = true
126
122
  end
@@ -27,9 +27,13 @@ class Redis
27
27
  # @param [String] key
28
28
  # @param [Integer] start start index
29
29
  # @param [Integer] stop stop index
30
+ # @param [String, Symbol] scale the scale of the offset range
31
+ # e.g. 'BYTE' - interpreted as a range of bytes, 'BIT' - interpreted as a range of bits
30
32
  # @return [Integer] the number of bits set to 1
31
- def bitcount(key, start = 0, stop = -1)
32
- send_command([:bitcount, key, start, stop])
33
+ def bitcount(key, start = 0, stop = -1, scale: nil)
34
+ command = [:bitcount, key, start, stop]
35
+ command << scale if scale
36
+ send_command(command)
33
37
  end
34
38
 
35
39
  # Perform a bitwise operation between strings and store the resulting string in a key.
@@ -51,14 +55,17 @@ class Redis
51
55
  # @param [Integer] bit whether to look for the first 1 or 0 bit
52
56
  # @param [Integer] start start index
53
57
  # @param [Integer] stop stop index
58
+ # @param [String, Symbol] scale the scale of the offset range
59
+ # e.g. 'BYTE' - interpreted as a range of bytes, 'BIT' - interpreted as a range of bits
54
60
  # @return [Integer] the position of the first 1/0 bit.
55
61
  # -1 if looking for 1 and it is not found or start and stop are given.
56
- def bitpos(key, bit, start = nil, stop = nil)
62
+ def bitpos(key, bit, start = nil, stop = nil, scale: nil)
57
63
  raise(ArgumentError, 'stop parameter specified without start parameter') if stop && !start
58
64
 
59
65
  command = [:bitpos, key, bit]
60
66
  command << start if start
61
67
  command << stop if stop
68
+ command << scale if scale
62
69
  send_command(command)
63
70
  end
64
71
  end
@@ -105,6 +105,14 @@ class Redis
105
105
  send_command(args, &Boolify)
106
106
  end
107
107
 
108
+ # Get a key's expiry time specified as number of seconds from UNIX Epoch
109
+ #
110
+ # @param [String] key
111
+ # @return [Integer] expiry time specified as number of seconds from UNIX Epoch
112
+ def expiretime(key)
113
+ send_command([:expiretime, key])
114
+ end
115
+
108
116
  # Get the time to live (in seconds) for a key.
109
117
  #
110
118
  # @param [String] key
@@ -161,6 +169,14 @@ class Redis
161
169
  send_command(args, &Boolify)
162
170
  end
163
171
 
172
+ # Get a key's expiry time specified as number of milliseconds from UNIX Epoch
173
+ #
174
+ # @param [String] key
175
+ # @return [Integer] expiry time specified as number of milliseconds from UNIX Epoch
176
+ def pexpiretime(key)
177
+ send_command([:pexpiretime, key])
178
+ end
179
+
164
180
  # Get the time to live (in milliseconds) for a key.
165
181
  #
166
182
  # @param [String] key
@@ -49,6 +49,27 @@ class Redis
49
49
  def pubsub(subcommand, *args)
50
50
  send_command([:pubsub, subcommand] + args)
51
51
  end
52
+
53
+ # Post a message to a channel in a shard.
54
+ def spublish(channel, message)
55
+ send_command([:spublish, channel, message])
56
+ end
57
+
58
+ # Listen for messages published to the given channels in a shard.
59
+ def ssubscribe(*channels, &block)
60
+ _subscription(:ssubscribe, 0, channels, block)
61
+ end
62
+
63
+ # Listen for messages published to the given channels in a shard.
64
+ # Throw a timeout error if there is no messages for a timeout period.
65
+ def ssubscribe_with_timeout(timeout, *channels, &block)
66
+ _subscription(:ssubscribe_with_timeout, timeout, channels, block)
67
+ end
68
+
69
+ # Stop listening for messages posted to the given channels in a shard.
70
+ def sunsubscribe(*channels)
71
+ _subscription(:sunsubscribe, 0, channels, nil)
72
+ end
52
73
  end
53
74
  end
54
75
  end
@@ -130,6 +130,11 @@ class Redis
130
130
  node_for(key).expireat(key, unix_time, **kwargs)
131
131
  end
132
132
 
133
+ # Get the expiration for a key as a UNIX timestamp.
134
+ def expiretime(key)
135
+ node_for(key).expiretime(key)
136
+ end
137
+
133
138
  # Get the time to live (in seconds) for a key.
134
139
  def ttl(key)
135
140
  node_for(key).ttl(key)
@@ -145,6 +150,11 @@ class Redis
145
150
  node_for(key).pexpireat(key, ms_unix_time, **kwarg)
146
151
  end
147
152
 
153
+ # Get the expiration for a key as number of milliseconds from UNIX Epoch.
154
+ def pexpiretime(key)
155
+ node_for(key).pexpiretime(key)
156
+ end
157
+
148
158
  # Get the time to live (in milliseconds) for a key.
149
159
  def pttl(key)
150
160
  node_for(key).pttl(key)
@@ -370,8 +380,8 @@ class Redis
370
380
  end
371
381
 
372
382
  # Count the number of set bits in a range of the string value stored at key.
373
- def bitcount(key, start = 0, stop = -1)
374
- node_for(key).bitcount(key, start, stop)
383
+ def bitcount(key, start = 0, stop = -1, scale: nil)
384
+ node_for(key).bitcount(key, start, stop, scale: scale)
375
385
  end
376
386
 
377
387
  # Perform a bitwise operation between strings and store the resulting string in a key.
@@ -383,8 +393,8 @@ class Redis
383
393
  end
384
394
 
385
395
  # Return the position of the first bit set to 1 or 0 in a string.
386
- def bitpos(key, bit, start = nil, stop = nil)
387
- node_for(key).bitpos(key, bit, start, stop)
396
+ def bitpos(key, bit, start = nil, stop = nil, scale: nil)
397
+ node_for(key).bitpos(key, bit, start, stop, scale: scale)
388
398
  end
389
399
 
390
400
  # Set the string value of a key and return its old value.
@@ -29,6 +29,14 @@ class Redis
29
29
  subscription("psubscribe", "punsubscribe", channels, block, timeout)
30
30
  end
31
31
 
32
+ def ssubscribe(*channels, &block)
33
+ subscription("ssubscribe", "sunsubscribe", channels, block)
34
+ end
35
+
36
+ def ssubscribe_with_timeout(timeout, *channels, &block)
37
+ subscription("ssubscribe", "sunsubscribe", channels, block, timeout)
38
+ end
39
+
32
40
  def unsubscribe(*channels)
33
41
  call_v([:unsubscribe, *channels])
34
42
  end
@@ -37,6 +45,10 @@ class Redis
37
45
  call_v([:punsubscribe, *channels])
38
46
  end
39
47
 
48
+ def sunsubscribe(*channels)
49
+ call_v([:sunsubscribe, *channels])
50
+ end
51
+
40
52
  def close
41
53
  @client.close
42
54
  end
@@ -46,7 +58,11 @@ class Redis
46
58
  def subscription(start, stop, channels, block, timeout = 0)
47
59
  sub = Subscription.new(&block)
48
60
 
49
- call_v([start, *channels])
61
+ case start
62
+ when "ssubscribe" then channels.each { |c| call_v([start, c]) } # avoid cross-slot keys
63
+ else call_v([start, *channels])
64
+ end
65
+
50
66
  while event = @client.next_event(timeout)
51
67
  if event.is_a?(::RedisClient::CommandError)
52
68
  raise Client::ERROR_MAPPING.fetch(event.class), event.message
@@ -94,5 +110,17 @@ class Redis
94
110
  def pmessage(&block)
95
111
  @callbacks["pmessage"] = block
96
112
  end
113
+
114
+ def ssubscribe(&block)
115
+ @callbacks["ssubscribe"] = block
116
+ end
117
+
118
+ def sunsubscribe(&block)
119
+ @callbacks["sunsubscribe"] = block
120
+ end
121
+
122
+ def smessage(&block)
123
+ @callbacks["smessage"] = block
124
+ end
97
125
  end
98
126
  end
data/lib/redis/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Redis
4
- VERSION = '5.0.7'
4
+ VERSION = '5.1.0'
5
5
  end
data/lib/redis.rb CHANGED
@@ -45,7 +45,7 @@ class Redis
45
45
  # @option options [String] :host ("127.0.0.1") server hostname
46
46
  # @option options [Integer] :port (6379) server port
47
47
  # @option options [String] :path path to server socket (overrides host and port)
48
- # @option options [Float] :timeout (5.0) timeout in seconds
48
+ # @option options [Float] :timeout (1.0) timeout in seconds
49
49
  # @option options [Float] :connect_timeout (same as timeout) timeout for initial connect in seconds
50
50
  # @option options [String] :username Username to authenticate against server
51
51
  # @option options [String] :password Password to authenticate against server
@@ -137,21 +137,6 @@ class Redis
137
137
  end
138
138
 
139
139
  if options.key?(:sentinels)
140
- if url = options.delete(:url)
141
- uri = URI.parse(url)
142
- if !options.key?(:name) && uri.host
143
- options[:name] = uri.host
144
- end
145
-
146
- if !options.key?(:password) && uri.password && !uri.password.empty?
147
- options[:password] = uri.password
148
- end
149
-
150
- if !options.key?(:username) && uri.user && !uri.user.empty?
151
- options[:username] = uri.user
152
- end
153
- end
154
-
155
140
  Client.sentinel(**options).new_client
156
141
  else
157
142
  Client.config(**options).new_client
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: 5.0.7
4
+ version: 5.1.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: 2023-08-09 00:00:00.000000000 Z
19
+ date: 2024-02-09 00:00:00.000000000 Z
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  name: redis-client
@@ -24,14 +24,14 @@ dependencies:
24
24
  requirements:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
- version: 0.9.0
27
+ version: 0.17.0
28
28
  type: :runtime
29
29
  prerelease: false
30
30
  version_requirements: !ruby/object:Gem::Requirement
31
31
  requirements:
32
32
  - - ">="
33
33
  - !ruby/object:Gem::Version
34
- version: 0.9.0
34
+ version: 0.17.0
35
35
  description: |2
36
36
  A Ruby client that tries to match Redis' API one-to-one, while still
37
37
  providing an idiomatic interface.
@@ -75,9 +75,9 @@ licenses:
75
75
  metadata:
76
76
  bug_tracker_uri: https://github.com/redis/redis-rb/issues
77
77
  changelog_uri: https://github.com/redis/redis-rb/blob/master/CHANGELOG.md
78
- documentation_uri: https://www.rubydoc.info/gems/redis/5.0.7
78
+ documentation_uri: https://www.rubydoc.info/gems/redis/5.1.0
79
79
  homepage_uri: https://github.com/redis/redis-rb
80
- source_code_uri: https://github.com/redis/redis-rb/tree/v5.0.7
80
+ source_code_uri: https://github.com/redis/redis-rb/tree/v5.1.0
81
81
  post_install_message:
82
82
  rdoc_options: []
83
83
  require_paths: