redis 4.1.0 → 4.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +171 -0
- data/README.md +106 -27
- data/lib/redis/client.rb +151 -95
- data/lib/redis/cluster/command.rb +4 -6
- data/lib/redis/cluster/command_loader.rb +8 -9
- data/lib/redis/cluster/node.rb +17 -1
- data/lib/redis/cluster/node_key.rb +3 -7
- data/lib/redis/cluster/node_loader.rb +8 -11
- data/lib/redis/cluster/option.rb +38 -15
- data/lib/redis/cluster/slot.rb +30 -13
- data/lib/redis/cluster/slot_loader.rb +12 -15
- data/lib/redis/cluster.rb +46 -17
- data/lib/redis/commands/bitmaps.rb +63 -0
- data/lib/redis/commands/cluster.rb +45 -0
- data/lib/redis/commands/connection.rb +58 -0
- data/lib/redis/commands/geo.rb +84 -0
- data/lib/redis/commands/hashes.rb +251 -0
- data/lib/redis/commands/hyper_log_log.rb +37 -0
- data/lib/redis/commands/keys.rb +411 -0
- data/lib/redis/commands/lists.rb +289 -0
- data/lib/redis/commands/pubsub.rb +72 -0
- data/lib/redis/commands/scripting.rb +114 -0
- data/lib/redis/commands/server.rb +188 -0
- data/lib/redis/commands/sets.rb +207 -0
- data/lib/redis/commands/sorted_sets.rb +812 -0
- data/lib/redis/commands/streams.rb +382 -0
- data/lib/redis/commands/strings.rb +313 -0
- data/lib/redis/commands/transactions.rb +139 -0
- data/lib/redis/commands.rb +242 -0
- data/lib/redis/connection/command_helper.rb +5 -2
- data/lib/redis/connection/hiredis.rb +7 -7
- data/lib/redis/connection/registry.rb +2 -1
- data/lib/redis/connection/ruby.rb +135 -110
- data/lib/redis/connection/synchrony.rb +17 -10
- data/lib/redis/connection.rb +3 -1
- data/lib/redis/distributed.rb +209 -70
- data/lib/redis/errors.rb +11 -0
- data/lib/redis/hash_ring.rb +15 -14
- data/lib/redis/pipeline.rb +172 -9
- data/lib/redis/subscribe.rb +11 -12
- data/lib/redis/version.rb +3 -1
- data/lib/redis.rb +171 -3375
- metadata +32 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 185ccbe36adc1e1561474af65d0e0b8d246e9c161757c9218f5ac7b6c1d24bb9
|
4
|
+
data.tar.gz: 03a4203747503b971551500ea40f996cb9620e5d9a693231d7a63944a9f73bf8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3354c910dcf3feb76b7f4ed7adb5bcce4f1cfc3ef7c58347897ba4705337a89052d2db67a8a71765f34e16f01a7ab2c8894bba60a3a89e1f36b6487f3fe0089b
|
7
|
+
data.tar.gz: 0b23396f9ecf62dd952536b94107a7748bb5ee225e7c7ac1da36e813e7fffc588c5939abe1800fc440e173acc54a9ac3649037b62b3ff59aa946ffc9a3e11180
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,176 @@
|
|
1
1
|
# Unreleased
|
2
2
|
|
3
|
+
# 4.7.1
|
4
|
+
|
5
|
+
* Gracefully handle OpenSSL 3.0 EOF Errors (`OpenSSL::SSL::SSLError: SSL_read: unexpected eof while reading`). See #1106
|
6
|
+
This happens frequently on heroku-22.
|
7
|
+
|
8
|
+
# 4.7.0
|
9
|
+
|
10
|
+
* Support single endpoint architecture with SSL/TLS in cluster mode. See #1086.
|
11
|
+
* `zrem` and `zadd` act as noop when provided an empty list of keys. See #1097.
|
12
|
+
* Support IPv6 URLs.
|
13
|
+
* Add `Redis#with` for better compatibility with `connection_pool` usage.
|
14
|
+
* Fix the block form of `multi` called inside `pipelined`. Previously the `MUTLI/EXEC` wouldn't be sent. See #1073.
|
15
|
+
|
16
|
+
# 4.6.0
|
17
|
+
|
18
|
+
* Deprecate `Redis.current`.
|
19
|
+
* Deprecate calling commands on `Redis` inside `Redis#pipelined`. See #1059.
|
20
|
+
```ruby
|
21
|
+
redis.pipelined do
|
22
|
+
redis.get("key")
|
23
|
+
end
|
24
|
+
```
|
25
|
+
|
26
|
+
should be replaced by:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
redis.pipelined do |pipeline|
|
30
|
+
pipeline.get("key")
|
31
|
+
end
|
32
|
+
```
|
33
|
+
* Deprecate calling commands on `Redis` inside `Redis#multi`. See #1059.
|
34
|
+
```ruby
|
35
|
+
redis.multi do
|
36
|
+
redis.get("key")
|
37
|
+
end
|
38
|
+
```
|
39
|
+
|
40
|
+
should be replaced by:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
redis.multi do |transaction|
|
44
|
+
transaction.get("key")
|
45
|
+
end
|
46
|
+
```
|
47
|
+
* Deprecate `Redis#queue` and `Redis#commit`. See #1059.
|
48
|
+
|
49
|
+
* Fix `zpopmax` and `zpopmin` when called inside a pipeline. See #1055.
|
50
|
+
* `Redis#synchronize` is now private like it should always have been.
|
51
|
+
|
52
|
+
* Add `Redis.silence_deprecations=` to turn off deprecation warnings.
|
53
|
+
If you don't wish to see warnings yet, you can set `Redis.silence_deprecations = true`.
|
54
|
+
It is however heavily recommended to fix them instead when possible.
|
55
|
+
* Add `Redis.raise_deprecations=` to turn deprecation warnings into errors.
|
56
|
+
This makes it easier to identitify the source of deprecated APIs usage.
|
57
|
+
It is recommended to set `Redis.raise_deprecations = true` in development and test environments.
|
58
|
+
* Add new options to ZRANGE. See #1053.
|
59
|
+
* Add ZRANGESTORE command. See #1053.
|
60
|
+
* Add SCAN support for `Redis::Cluster`. See #1049.
|
61
|
+
* Add COPY command. See #1053. See #1048.
|
62
|
+
* Add ZDIFFSTORE command. See #1046.
|
63
|
+
* Add ZDIFF command. See #1044.
|
64
|
+
* Add ZUNION command. See #1042.
|
65
|
+
* Add HRANDFIELD command. See #1040.
|
66
|
+
|
67
|
+
# 4.5.1
|
68
|
+
|
69
|
+
* Restore the accidential auth behavior of redis-rb 4.3.0 with a warning. If provided with the `default` user's password, but a wrong username,
|
70
|
+
redis-rb will first try to connect as the provided user, but then will fallback to connect as the `default` user with the provided password.
|
71
|
+
This behavior is deprecated and will be removed in Redis 4.6.0. Fix #1038.
|
72
|
+
|
73
|
+
# 4.5.0
|
74
|
+
|
75
|
+
* Handle parts of the command using incompatible encodings. See #1037.
|
76
|
+
* Add GET option to SET command. See #1036.
|
77
|
+
* Add ZRANDMEMBER command. See #1035.
|
78
|
+
* Add LMOVE/BLMOVE commands. See #1034.
|
79
|
+
* Add ZMSCORE command. See #1032.
|
80
|
+
* Add LT/GT options to ZADD. See #1033.
|
81
|
+
* Add SMISMEMBER command. See #1031.
|
82
|
+
* Add EXAT/PXAT options to SET. See #1028.
|
83
|
+
* Add GETDEL/GETEX commands. See #1024.
|
84
|
+
* `Redis#exists` now returns an Integer by default, as warned since 4.2.0. The old behavior can be restored with `Redis.exists_returns_integer = false`.
|
85
|
+
* Fix Redis < 6 detection during connect. See #1025.
|
86
|
+
* Fix fetching command details in Redis cluster when the first node is unhealthy. See #1026.
|
87
|
+
|
88
|
+
# 4.4.0
|
89
|
+
|
90
|
+
* Redis cluster: fix cross-slot validation in pipelines. Fix ##1019.
|
91
|
+
* Add support for `XAUTOCLAIM`. See #1018.
|
92
|
+
* Properly issue `READONLY` when reconnecting to replicas. Fix #1017.
|
93
|
+
* Make `del` a noop if passed an empty list of keys. See #998.
|
94
|
+
* Add support for `ZINTER`. See #995.
|
95
|
+
|
96
|
+
# 4.3.1
|
97
|
+
|
98
|
+
* Fix password authentication against redis server 5 and older.
|
99
|
+
|
100
|
+
# 4.3.0
|
101
|
+
|
102
|
+
* Add the TYPE argument to scan and scan_each. See #985.
|
103
|
+
* Support AUTH command for ACL. See #967.
|
104
|
+
|
105
|
+
# 4.2.5
|
106
|
+
|
107
|
+
* Optimize the ruby connector write buffering. See #964.
|
108
|
+
|
109
|
+
# 4.2.4
|
110
|
+
|
111
|
+
* Fix bytesize calculations in the ruby connector, and work on a copy of the buffer. Fix #961, #962.
|
112
|
+
|
113
|
+
# 4.2.3
|
114
|
+
|
115
|
+
* Use io/wait instead of IO.select in the ruby connector. See #960.
|
116
|
+
* Use exception free non blocking IOs in the ruby connector. See #926.
|
117
|
+
* Prevent corruption of the client when an interrupt happen during inside a pipeline block. See #945.
|
118
|
+
|
119
|
+
# 4.2.2
|
120
|
+
|
121
|
+
* Fix `WATCH` support for `Redis::Distributed`. See #941.
|
122
|
+
* Fix handling of empty stream responses. See #905, #929.
|
123
|
+
|
124
|
+
# 4.2.1
|
125
|
+
|
126
|
+
* Fix `exists?` returning an actual boolean when called with multiple keys. See #918.
|
127
|
+
* Setting `Redis.exists_returns_integer = false` disables warning message about new behaviour. See #920.
|
128
|
+
|
129
|
+
# 4.2.0
|
130
|
+
|
131
|
+
* Convert commands to accept keyword arguments rather than option hashes. This both help catching typos, and reduce needless allocations.
|
132
|
+
* Deprecate the synchrony driver. It will be removed in 5.0 and hopefully maintained as a separate gem. See #915.
|
133
|
+
* Make `Redis#exists` variadic, will return an Integer if called with multiple keys.
|
134
|
+
* Add `Redis#exists?` to get a Boolean if any of the keys exists.
|
135
|
+
* `Redis#exists` when called with a single key will warn that future versions will return an Integer.
|
136
|
+
Set `Redis.exists_returns_integer = true` to opt-in to the new behavior.
|
137
|
+
* Support `keepttl` ooption in `set`. See #913.
|
138
|
+
* Optimized initialization of Redis::Cluster. See #912.
|
139
|
+
* Accept sentinel options even with string key. See #599.
|
140
|
+
* Verify TLS connections by default. See #900.
|
141
|
+
* Make `Redis#hset` variadic. It now returns an integer, not a boolean. See #910.
|
142
|
+
|
143
|
+
# 4.1.4
|
144
|
+
|
145
|
+
* Alias `Redis#disconnect` as `#close`. See #901.
|
146
|
+
* Handle clusters with multiple slot ranges. See #894.
|
147
|
+
* Fix password authentication to a redis cluster. See #889.
|
148
|
+
* Handle recursive MOVED responses. See #882.
|
149
|
+
* Increase buffer size in the ruby connector. See #880.
|
150
|
+
* Fix thread safety of `Redis.queue`. See #878.
|
151
|
+
* Deprecate `Redis::Future#==` as it's likely to be a mistake. See #876.
|
152
|
+
* Support `KEEPTTL` option for SET command. See #913.
|
153
|
+
|
154
|
+
# 4.1.3
|
155
|
+
|
156
|
+
* Fix the client hanging forever when connecting with SSL to a non-SSL server. See #835.
|
157
|
+
|
158
|
+
# 4.1.2
|
159
|
+
|
160
|
+
* Fix several authentication problems with sentinel. See #850 and #856.
|
161
|
+
* Explicitly drop Ruby 2.2 support.
|
162
|
+
|
163
|
+
|
164
|
+
# 4.1.1
|
165
|
+
|
166
|
+
* Fix error handling in multi blocks. See #754.
|
167
|
+
* Fix geoadd to accept arrays like georadius and georadiusbymember. See #841.
|
168
|
+
* Fix georadius command failing when long == lat. See #841.
|
169
|
+
* Fix timeout error in xread block: 0. See #837.
|
170
|
+
* Fix incompatibility issue with redis-objects. See #834.
|
171
|
+
* Properly handle Errno::EADDRNOTAVAIL on connect.
|
172
|
+
* Fix password authentication to sentinel instances. See #813.
|
173
|
+
|
3
174
|
# 4.1.0
|
4
175
|
|
5
176
|
* Add Redis Cluster support. See #716.
|
data/README.md
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
-
# redis-rb [![Build Status][
|
1
|
+
# redis-rb [![Build Status][gh-actions-image]][gh-actions-link] [![Inline docs][inchpages-image]][inchpages-link]
|
2
2
|
|
3
3
|
A Ruby client that tries to match [Redis][redis-home]' API one-to-one, while still
|
4
4
|
providing an idiomatic interface.
|
5
5
|
|
6
|
+
See [RubyDoc.info][rubydoc] for the API docs of the latest published gem.
|
6
7
|
|
7
8
|
## Getting started
|
8
9
|
|
@@ -34,6 +35,9 @@ You can also specify connection options as a [`redis://` URL][redis-url]:
|
|
34
35
|
redis = Redis.new(url: "redis://:p4ssw0rd@10.0.1.1:6380/15")
|
35
36
|
```
|
36
37
|
|
38
|
+
The client expects passwords with special chracters to be URL-encoded (i.e.
|
39
|
+
`CGI.escape(password)`).
|
40
|
+
|
37
41
|
By default, the client will try to read the `REDIS_URL` environment variable
|
38
42
|
and use that as URL to connect to. The above statement is therefore equivalent
|
39
43
|
to setting this environment variable and calling `Redis.new` without arguments.
|
@@ -50,6 +54,12 @@ To connect to a password protected Redis instance, use:
|
|
50
54
|
redis = Redis.new(password: "mysecret")
|
51
55
|
```
|
52
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')
|
61
|
+
```
|
62
|
+
|
53
63
|
The Redis class exports methods that are named identical to the commands
|
54
64
|
they execute. The arguments these methods accept are often identical to
|
55
65
|
the arguments specified on the [Redis website][redis-commands]. For
|
@@ -95,10 +105,75 @@ but a few so that if one is down the client will try the next one. The client
|
|
95
105
|
is able to remember the last Sentinel that was able to reply correctly and will
|
96
106
|
use it for the next requests.
|
97
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
|
+
|
158
|
+
## Cluster mode with SSL/TLS
|
159
|
+
Since Redis can return FQDN of nodes in reply to client since `7.*` with CLUSTER commands, we can use cluster feature with SSL/TLS connection like this:
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
Redis.new(cluster: %w[rediss://foo.example.com:6379])
|
163
|
+
```
|
164
|
+
|
165
|
+
On the other hand, in Redis versions prior to `6.*`, you can specify options like the following if cluster mode is enabled and client has to connect to nodes via single endpoint with SSL/TLS.
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
Redis.new(cluster: %w[rediss://foo-endpoint.example.com:6379], fixed_hostname: 'foo-endpoint.example.com')
|
169
|
+
```
|
170
|
+
|
171
|
+
In case of the above architecture, if you don't pass the `fixed_hostname` option to the client and servers return IP addresses of nodes, the client may fail to verify certificates.
|
172
|
+
|
98
173
|
## Storing objects
|
99
174
|
|
100
|
-
Redis
|
101
|
-
|
175
|
+
Redis "string" types can be used to store serialized Ruby objects, for
|
176
|
+
example with JSON:
|
102
177
|
|
103
178
|
```ruby
|
104
179
|
require "json"
|
@@ -124,9 +199,9 @@ commands to Redis and gathers their replies. These replies are returned
|
|
124
199
|
by the `#pipelined` method.
|
125
200
|
|
126
201
|
```ruby
|
127
|
-
redis.pipelined do
|
128
|
-
|
129
|
-
|
202
|
+
redis.pipelined do |pipeline|
|
203
|
+
pipeline.set "foo", "bar"
|
204
|
+
pipeline.incr "baz"
|
130
205
|
end
|
131
206
|
# => ["OK", 1]
|
132
207
|
```
|
@@ -140,9 +215,9 @@ the regular pipeline, the replies to the commands are returned by the
|
|
140
215
|
`#multi` method.
|
141
216
|
|
142
217
|
```ruby
|
143
|
-
redis.multi do
|
144
|
-
|
145
|
-
|
218
|
+
redis.multi do |transaction|
|
219
|
+
transaction.set "foo", "bar"
|
220
|
+
transaction.incr "baz"
|
146
221
|
end
|
147
222
|
# => ["OK", 1]
|
148
223
|
```
|
@@ -150,15 +225,15 @@ end
|
|
150
225
|
### Futures
|
151
226
|
|
152
227
|
Replies to commands in a pipeline can be accessed via the *futures* they
|
153
|
-
emit (since redis-rb 3.0). All calls
|
228
|
+
emit (since redis-rb 3.0). All calls on the pipeline object return a
|
154
229
|
`Future` object, which responds to the `#value` method. When the
|
155
230
|
pipeline has successfully executed, all futures are assigned their
|
156
231
|
respective replies and can be used.
|
157
232
|
|
158
233
|
```ruby
|
159
|
-
redis.pipelined do
|
160
|
-
@set =
|
161
|
-
@incr =
|
234
|
+
redis.pipelined do |pipeline|
|
235
|
+
@set = pipeline.set "foo", "bar"
|
236
|
+
@incr = pipeline.incr "baz"
|
162
237
|
end
|
163
238
|
|
164
239
|
@set.value
|
@@ -211,6 +286,7 @@ All timeout values are specified in seconds.
|
|
211
286
|
When using pub/sub, you can subscribe to a channel using a timeout as well:
|
212
287
|
|
213
288
|
```ruby
|
289
|
+
redis = Redis.new(reconnect_attempts: 0)
|
214
290
|
redis.subscribe_with_timeout(5, "news") do |on|
|
215
291
|
on.message do |channel, message|
|
216
292
|
# ...
|
@@ -272,7 +348,7 @@ This library supports natively terminating client side SSL/TLS connections
|
|
272
348
|
when talking to Redis via a server-side proxy such as [stunnel], [hitch],
|
273
349
|
or [ghostunnel].
|
274
350
|
|
275
|
-
To enable SSL support, pass the `:ssl =>
|
351
|
+
To enable SSL support, pass the `:ssl => true` option when configuring the
|
276
352
|
Redis client, or pass in `:url => "rediss://..."` (like HTTPS for Redis).
|
277
353
|
You will also need to pass in an `:ssl_params => { ... }` hash used to
|
278
354
|
configure the `OpenSSL::SSL::SSLContext` object used for the connection:
|
@@ -385,7 +461,11 @@ redis = Redis.new(:driver => :synchrony)
|
|
385
461
|
## Testing
|
386
462
|
|
387
463
|
This library is tested against recent Ruby and Redis versions.
|
388
|
-
Check [
|
464
|
+
Check [Github Actions][gh-actions-link] for the exact versions supported.
|
465
|
+
|
466
|
+
## See Also
|
467
|
+
|
468
|
+
- [async-redis](https://github.com/socketry/async-redis) — An [async](https://github.com/socketry/async) compatible Redis client.
|
389
469
|
|
390
470
|
## Contributors
|
391
471
|
|
@@ -397,15 +477,14 @@ client and evangelized Redis in Rubyland. Thank you, Ezra.
|
|
397
477
|
## Contributing
|
398
478
|
|
399
479
|
[Fork the project](https://github.com/redis/redis-rb) and send pull
|
400
|
-
requests.
|
401
|
-
|
402
|
-
|
403
|
-
[inchpages-image]:
|
404
|
-
[inchpages-link]:
|
405
|
-
[redis-commands]:
|
406
|
-
[redis-home]:
|
407
|
-
[redis-url]:
|
408
|
-
[
|
409
|
-
[
|
410
|
-
[
|
411
|
-
[rubydoc]: http://www.rubydoc.info/gems/redis
|
480
|
+
requests.
|
481
|
+
|
482
|
+
|
483
|
+
[inchpages-image]: https://inch-ci.org/github/redis/redis-rb.svg
|
484
|
+
[inchpages-link]: https://inch-ci.org/github/redis/redis-rb
|
485
|
+
[redis-commands]: https://redis.io/commands
|
486
|
+
[redis-home]: https://redis.io
|
487
|
+
[redis-url]: http://www.iana.org/assignments/uri-schemes/prov/redis
|
488
|
+
[gh-actions-image]: https://github.com/redis/redis-rb/workflows/Test/badge.svg
|
489
|
+
[gh-actions-link]: https://github.com/redis/redis-rb/actions
|
490
|
+
[rubydoc]: http://www.rubydoc.info/gems/redis
|