async-redis 0.10.1 → 0.11.1

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: da847e343c291506a20337eec6170867a0e0bf295b713ece60fd7f48928d873f
4
- data.tar.gz: 2ea6e2720f556084f57415501a1964c0bb2a93a411a9cb52138dbb8ed141c45b
3
+ metadata.gz: 1a6afd9e0917905a3ac88663aab6185431af4f90230a160439131b137611a072
4
+ data.tar.gz: 503e41aea7adc5f2f103d442db5be4c37f9299c9fb9bbba33b040f8200237511
5
5
  SHA512:
6
- metadata.gz: 9ac74325525a0dc00b06aaee1fa505566bce74f4806c07f26a8581ac7b20db79f11cbb052d6d598d02b7eec94aae6a142d88da00eb01e4b0a8d72e134ef5a798
7
- data.tar.gz: 2b873fd8ee1cfffda74d301265ec9477a34dfe571d30d4c36d195cf39b089c22635bc74c07ade143ca46a5e169d0db226470a6149ce912be3b3da0db96e26b49
6
+ metadata.gz: 459502e1c7c5cfbb6250a4460f1dfa4b5e0cd2386e056f77696883521274d3ad0b6c25cd5a1e6ee3db393d18703782c643c1fe6b39e4cf22292cd26417b6af9b
7
+ data.tar.gz: 3119cf4d3b60ed724b68ed9fa2fc9dee2729a27657ebf1460453d236426d8e1c19f3f1717c5d0266fb85a9c7f821ca1e74f3e1e2321750b71805ecbefe084387
checksums.yaml.gz.sig CHANGED
Binary file
@@ -7,16 +7,16 @@
7
7
  # Copyright, 2019, by David Ortiz.
8
8
  # Copyright, 2020, by Salim Semaoune.
9
9
 
10
- require_relative 'context/pipeline'
11
- require_relative 'context/transaction'
12
- require_relative 'context/subscribe'
13
- require_relative 'endpoint'
10
+ require_relative "context/pipeline"
11
+ require_relative "context/transaction"
12
+ require_relative "context/subscribe"
13
+ require_relative "endpoint"
14
14
 
15
- require 'io/endpoint/host_endpoint'
16
- require 'async/pool/controller'
17
- require 'protocol/redis/methods'
15
+ require "io/endpoint/host_endpoint"
16
+ require "async/pool/controller"
17
+ require "protocol/redis/methods"
18
18
 
19
- require 'io/stream'
19
+ require "io/stream"
20
20
 
21
21
  module Async
22
22
  module Redis
@@ -89,7 +89,7 @@ module Async
89
89
  @endpoint = endpoint
90
90
  @protocol = protocol
91
91
 
92
- @pool = connect(**options)
92
+ @pool = make_pool(**options)
93
93
  end
94
94
 
95
95
  attr :endpoint
@@ -113,7 +113,14 @@ module Async
113
113
 
114
114
  protected
115
115
 
116
- def connect(**options)
116
+ def assign_default_tags(tags)
117
+ tags[:endpoint] = @endpoint.to_s
118
+ tags[:protocol] = @protocol.to_s
119
+ end
120
+
121
+ def make_pool(**options)
122
+ self.assign_default_tags(options[:tags] ||= {})
123
+
117
124
  Async::Pool::Controller.wrap(**options) do
118
125
  peer = @endpoint.connect
119
126
 
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2020, by David Ortiz.
5
- # Copyright, 2023-2024, by Samuel Williams.
4
+ # Copyright, 2024-2025, by Samuel Williams.
5
+ # Copyright, 2025, by Travis Bell.
6
6
 
7
- require_relative 'client'
8
- require 'io/stream'
7
+ require_relative "client"
8
+ require "io/stream"
9
9
 
10
10
  module Async
11
11
  module Redis
@@ -57,6 +57,7 @@ module Async
57
57
  # @property endpoints [Array(Endpoint)] The list of cluster endpoints.
58
58
  def initialize(endpoints, **options)
59
59
  @endpoints = endpoints
60
+ @options = options
60
61
  @shards = nil
61
62
  end
62
63
 
@@ -94,7 +95,7 @@ module Async
94
95
  end
95
96
 
96
97
  if node = nodes.sample
97
- return (node.client ||= Client.new(node.endpoint))
98
+ return (node.client ||= Client.new(node.endpoint, **@options))
98
99
  end
99
100
  end
100
101
 
@@ -102,25 +103,25 @@ module Async
102
103
 
103
104
  def reload_cluster!(endpoints = @endpoints)
104
105
  @endpoints.each do |endpoint|
105
- client = Client.new(endpoint)
106
+ client = Client.new(endpoint, **@options)
106
107
 
107
108
  shards = RangeMap.new
108
109
  endpoints = []
109
110
 
110
- client.call('CLUSTER', 'SHARDS').each do |shard|
111
+ client.call("CLUSTER", "SHARDS").each do |shard|
111
112
  shard = shard.each_slice(2).to_h
112
113
 
113
- slots = shard['slots']
114
+ slots = shard["slots"]
114
115
  range = Range.new(*slots)
115
116
 
116
- nodes = shard['nodes'].map do |node|
117
+ nodes = shard["nodes"].map do |node|
117
118
  node = node.each_slice(2).to_h
118
- endpoint = Endpoint.remote(node['ip'], node['port'])
119
+ endpoint = Endpoint.remote(node["ip"], node["port"])
119
120
 
120
121
  # Collect all endpoints:
121
122
  endpoints << endpoint
122
123
 
123
- Node.new(node['id'], endpoint, node['role'].to_sym, node['health'].to_sym)
124
+ Node.new(node["id"], endpoint, node["role"].to_sym, node["health"].to_sym)
124
125
  end
125
126
 
126
127
  shards.add(range, nodes)
@@ -193,8 +194,8 @@ module Async
193
194
  def slot_for(key)
194
195
  key = key.to_s
195
196
 
196
- if s = key.index('{')
197
- if e = key.index('}', s + 1) and e != s + 1
197
+ if s = key.index("{")
198
+ if e = key.index("}", s + 1) and e != s + 1
198
199
  key = key[s + 1..e - 1]
199
200
  end
200
201
  end
@@ -2,9 +2,9 @@
2
2
 
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2019, by Mikael Henriksson.
5
- # Copyright, 2019-2023, by Samuel Williams.
5
+ # Copyright, 2019-2025, by Samuel Williams.
6
6
 
7
- require 'protocol/redis/methods'
7
+ require "protocol/redis/methods"
8
8
 
9
9
  module Async
10
10
  module Redis
@@ -5,7 +5,7 @@
5
5
  # Copyright, 2019-2024, by Samuel Williams.
6
6
  # Copyright, 2022, by Tim Willard.
7
7
 
8
- require_relative 'generic'
8
+ require_relative "generic"
9
9
 
10
10
  module Async
11
11
  module Redis
@@ -2,15 +2,15 @@
2
2
 
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2018, by Huba Nagy.
5
- # Copyright, 2018-2023, by Samuel Williams.
5
+ # Copyright, 2018-2024, by Samuel Williams.
6
6
 
7
- require_relative 'generic'
7
+ require_relative "generic"
8
8
 
9
9
  module Async
10
10
  module Redis
11
11
  module Context
12
12
  class Subscribe < Generic
13
- MESSAGE = 'message'
13
+ MESSAGE = "message"
14
14
 
15
15
  def initialize(pool, channels)
16
16
  super(pool)
@@ -31,13 +31,21 @@ module Async
31
31
  end
32
32
  end
33
33
 
34
+ def each
35
+ return to_enum unless block_given?
36
+
37
+ while response = self.listen
38
+ yield response
39
+ end
40
+ end
41
+
34
42
  def subscribe(channels)
35
- @connection.write_request ['SUBSCRIBE', *channels]
43
+ @connection.write_request ["SUBSCRIBE", *channels]
36
44
  @connection.flush
37
45
  end
38
46
 
39
47
  def unsubscribe(channels)
40
- @connection.write_request ['UNSUBSCRIBE', *channels]
48
+ @connection.write_request ["UNSUBSCRIBE", *channels]
41
49
  @connection.flush
42
50
  end
43
51
  end
@@ -2,9 +2,9 @@
2
2
 
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2018, by Huba Nagy.
5
- # Copyright, 2018-2023, by Samuel Williams.
5
+ # Copyright, 2018-2025, by Samuel Williams.
6
6
 
7
- require_relative 'pipeline'
7
+ require_relative "pipeline"
8
8
 
9
9
  module Async
10
10
  module Redis
@@ -15,20 +15,20 @@ module Async
15
15
  end
16
16
 
17
17
  def multi
18
- call('MULTI')
18
+ call("MULTI")
19
19
  end
20
20
 
21
21
  def watch(*keys)
22
- sync.call('WATCH', *keys)
22
+ sync.call("WATCH", *keys)
23
23
  end
24
24
 
25
25
  # Execute all queued commands, provided that no watched keys have been modified. It's important to note that even when a command fails, all the other commands in the queue are processed – Redis will not stop the processing of commands.
26
26
  def execute
27
- sync.call('EXEC')
27
+ sync.call("EXEC")
28
28
  end
29
29
 
30
30
  def discard
31
- sync.call('DISCARD')
31
+ sync.call("DISCARD")
32
32
  end
33
33
  end
34
34
  end
@@ -3,13 +3,13 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2024, by Samuel Williams.
5
5
 
6
- require 'io/endpoint'
7
- require 'io/endpoint/host_endpoint'
8
- require 'io/endpoint/ssl_endpoint'
6
+ require "io/endpoint"
7
+ require "io/endpoint/host_endpoint"
8
+ require "io/endpoint/ssl_endpoint"
9
9
 
10
- require_relative 'protocol/resp2'
11
- require_relative 'protocol/authenticated'
12
- require_relative 'protocol/selected'
10
+ require_relative "protocol/resp2"
11
+ require_relative "protocol/authenticated"
12
+ require_relative "protocol/selected"
13
13
 
14
14
  module Async
15
15
  module Redis
@@ -30,8 +30,8 @@ module Async
30
30
  end
31
31
 
32
32
  SCHEMES = {
33
- 'redis' => URI::Generic,
34
- 'rediss' => URI::Generic,
33
+ "redis" => URI::Generic,
34
+ "rediss" => URI::Generic,
35
35
  }
36
36
 
37
37
  def self.parse(string, endpoint = nil, **options)
@@ -117,7 +117,7 @@ module Async
117
117
  end
118
118
 
119
119
  def secure?
120
- ['rediss'].include?(self.scheme)
120
+ ["rediss"].include?(self.scheme)
121
121
  end
122
122
 
123
123
  def protocol
@@ -3,7 +3,7 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2024, by Samuel Williams.
5
5
 
6
- require 'protocol/redis'
6
+ require "protocol/redis"
7
7
 
8
8
  module Async
9
9
  module Redis
@@ -3,7 +3,7 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2018-2024, by Samuel Williams.
5
5
 
6
- require 'protocol/redis'
6
+ require "protocol/redis"
7
7
 
8
8
  module Async
9
9
  module Redis
@@ -3,7 +3,7 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2024, by Samuel Williams.
5
5
 
6
- require 'protocol/redis'
6
+ require "protocol/redis"
7
7
 
8
8
  module Async
9
9
  module Redis
@@ -3,14 +3,15 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2020, by David Ortiz.
5
5
  # Copyright, 2023-2024, by Samuel Williams.
6
+ # Copyright, 2024, by Joan Lledó.
6
7
 
7
- require_relative 'client'
8
- require 'io/stream'
8
+ require_relative "client"
9
+ require "io/stream"
9
10
 
10
11
  module Async
11
12
  module Redis
12
13
  class SentinelClient
13
- DEFAULT_MASTER_NAME = 'mymaster'
14
+ DEFAULT_MASTER_NAME = "mymaster"
14
15
 
15
16
  include ::Protocol::Redis::Methods
16
17
  include Client::Methods
@@ -30,7 +31,7 @@ module Async
30
31
  # A cache of sentinel connections.
31
32
  @sentinels = {}
32
33
 
33
- @pool = connect(**options)
34
+ @pool = make_pool(**options)
34
35
  end
35
36
 
36
37
  # @attribute [String] The name of the master instance.
@@ -64,26 +65,26 @@ module Async
64
65
 
65
66
  def failover(name = @master_name)
66
67
  sentinels do |client|
67
- return client.call('SENTINEL', 'FAILOVER', name)
68
+ return client.call("SENTINEL", "FAILOVER", name)
68
69
  end
69
70
  end
70
71
 
71
72
  def masters
72
73
  sentinels do |client|
73
- return client.call('SENTINEL', 'MASTERS').map{|fields| fields.each_slice(2).to_h}
74
+ return client.call("SENTINEL", "MASTERS").map{|fields| fields.each_slice(2).to_h}
74
75
  end
75
76
  end
76
77
 
77
78
  def master(name = @master_name)
78
79
  sentinels do |client|
79
- return client.call('SENTINEL', 'MASTER', name).each_slice(2).to_h
80
+ return client.call("SENTINEL", "MASTER", name).each_slice(2).to_h
80
81
  end
81
82
  end
82
83
 
83
84
  def resolve_master
84
85
  sentinels do |client|
85
86
  begin
86
- address = client.call('SENTINEL', 'GET-MASTER-ADDR-BY-NAME', @master_name)
87
+ address = client.call("SENTINEL", "GET-MASTER-ADDR-BY-NAME", @master_name)
87
88
  rescue Errno::ECONNREFUSED
88
89
  next
89
90
  end
@@ -97,7 +98,7 @@ module Async
97
98
  def resolve_slave
98
99
  sentinels do |client|
99
100
  begin
100
- reply = client.call('SENTINEL', 'SLAVES', @master_name)
101
+ reply = client.call("SENTINEL", "SLAVES", @master_name)
101
102
  rescue Errno::ECONNREFUSED
102
103
  next
103
104
  end
@@ -106,7 +107,7 @@ module Async
106
107
  next if slaves.empty?
107
108
 
108
109
  slave = select_slave(slaves)
109
- return Endpoint.remote(slave['ip'], slave['port'])
110
+ return Endpoint.remote(slave["ip"], slave["port"])
110
111
  end
111
112
 
112
113
  return nil
@@ -114,8 +115,14 @@ module Async
114
115
 
115
116
  protected
116
117
 
118
+ def assign_default_tags(tags)
119
+ tags[:protocol] = @protocol.to_s
120
+ end
121
+
117
122
  # Override the parent method. The only difference is that this one needs to resolve the master/slave address.
118
- def connect(**options)
123
+ def make_pool(**options)
124
+ self.assign_default_tags(options[:tags] ||= {})
125
+
119
126
  Async::Pool::Controller.wrap(**options) do
120
127
  endpoint = resolve_address
121
128
  peer = endpoint.connect
@@ -141,7 +148,7 @@ module Async
141
148
  slaves = reply.map{|fields| fields.each_slice(2).to_h}
142
149
 
143
150
  slaves.reject do |slave|
144
- slave['flags'].split(',').include?('s_down')
151
+ slave["flags"].split(",").include?("s_down")
145
152
  end
146
153
  end
147
154
 
@@ -5,6 +5,6 @@
5
5
 
6
6
  module Async
7
7
  module Redis
8
- VERSION = "0.10.1"
8
+ VERSION = "0.11.1"
9
9
  end
10
10
  end
data/lib/async/redis.rb CHANGED
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2018-2023, by Samuel Williams.
4
+ # Copyright, 2018-2024, by Samuel Williams.
5
5
  # Copyright, 2020, by David Ortiz.
6
6
 
7
- require_relative 'redis/version'
8
- require_relative 'redis/client'
7
+ require_relative "redis/version"
8
+ require_relative "redis/client"
9
9
 
10
- require_relative 'redis/cluster_client'
11
- require_relative 'redis/sentinel_client'
10
+ require_relative "redis/cluster_client"
11
+ require_relative "redis/sentinel_client"
data/license.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # MIT License
2
2
 
3
- Copyright, 2018-2024, by Samuel Williams.
3
+ Copyright, 2018-2025, by Samuel Williams.
4
4
  Copyright, 2018, by Huba Nagy.
5
5
  Copyright, 2019-2020, by David Ortiz.
6
6
  Copyright, 2019, by Pierre Montelle.
@@ -12,6 +12,8 @@ Copyright, 2021, by Olle Jonsson.
12
12
  Copyright, 2021, by Troex Nevelin.
13
13
  Copyright, 2022, by Tim Willard.
14
14
  Copyright, 2022, by Gleb Sinyavskiy.
15
+ Copyright, 2024, by Joan Lledó.
16
+ Copyright, 2025, by Travis Bell.
15
17
 
16
18
  Permission is hereby granted, free of charge, to any person obtaining a copy
17
19
  of this software and associated documentation files (the "Software"), to deal
data/readme.md CHANGED
@@ -4,12 +4,30 @@ An asynchronous client for Redis including TLS. Support for streaming requests a
4
4
 
5
5
  [![Development Status](https://github.com/socketry/async-redis/workflows/Test/badge.svg)](https://github.com/socketry/async-redis/actions?workflow=Test)
6
6
 
7
+ ## Support
8
+
9
+ This gem supports both Valkey and Redis. It is designed to be compatible with the latest versions of both libraries. We also test Redis sentinel and cluster configurations.
10
+
7
11
  ## Usage
8
12
 
9
13
  Please see the [project documentation](https://socketry.github.io/async-redis/) for more details.
10
14
 
11
15
  - [Getting Started](https://socketry.github.io/async-redis/guides/getting-started/index) - This guide explains how to use the `async-redis` gem to connect to a Redis server and perform basic operations.
12
16
 
17
+ ## Releases
18
+
19
+ Please see the [project releases](https://socketry.github.io/async-redis/releases/index) for all releases.
20
+
21
+ ### v0.11.1
22
+
23
+ - Correctly pass `@options` to `Async::Redis::Client` instances created by `Async::Redis::ClusterClient`.
24
+
25
+ ### v0.10.0
26
+
27
+ - [Add support for Redis Clusters](https://socketry.github.io/async-redis/releases/index#add-support-for-redis-clusters)
28
+ - [Add support for Redis Sentinels](https://socketry.github.io/async-redis/releases/index#add-support-for-redis-sentinels)
29
+ - [Improved Integration Tests](https://socketry.github.io/async-redis/releases/index#improved-integration-tests)
30
+
13
31
  ## Contributing
14
32
 
15
33
  We welcome contributions to this project.
@@ -1,10 +1,16 @@
1
- # v0.10.0
1
+ # Releases
2
2
 
3
- ## Cluster Client
3
+ ## v0.11.1
4
+
5
+ - Correctly pass `@options` to `Async::Redis::Client` instances created by `Async::Redis::ClusterClient`.
6
+
7
+ ## v0.10.0
8
+
9
+ ### Add support for Redis Clusters
4
10
 
5
11
  `Async::Redis::ClusterClient` is a new class that provides a high-level interface to a Redis Cluster. Due to the way clustering works, it does not provide the same interface as the `Async::Redis::Client` class. Instead, you must request an appropriate client for the key you are working with.
6
12
 
7
- ```ruby
13
+ ``` ruby
8
14
  endpoints = [
9
15
  Async::Redis::Endpoint.parse("redis://redis-a"),
10
16
  Async::Redis::Endpoint.parse("redis://redis-b"),
@@ -18,11 +24,11 @@ cluster_client.clients_for("key") do |client|
18
24
  end
19
25
  ```
20
26
 
21
- ## Sentinel Client
27
+ ### Add support for Redis Sentinels
22
28
 
23
29
  The previous implementation `Async::Redis::SentinelsClient` has been replaced with `Async::Redis::SentinelClient`. This new class uses `Async::Redis::Endpoint` objects to represent the sentinels and the master.
24
30
 
25
- ```ruby
31
+ ``` ruby
26
32
  sentinels = [
27
33
  Async::Redis::Endpoint.parse("redis://redis-sentinel-a"),
28
34
  Async::Redis::Endpoint.parse("redis://redis-sentinel-b"),
@@ -41,6 +47,6 @@ slave_client.session do |session|
41
47
  end
42
48
  ```
43
49
 
44
- ## Integration Tests
50
+ ### Improved Integration Tests
45
51
 
46
52
  Integration tests for Redis Cluster and Sentinel have been added, using `docker-compose` to start the required services and run the tests. These tests are not part of the default test suite and must be run separately. See the documentation in the `sentinel/` and `cluster/` directories for more information.
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-redis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.1
4
+ version: 0.11.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -12,11 +12,12 @@ authors:
12
12
  - Troex Nevelin
13
13
  - Alex Matchneer
14
14
  - Jeremy Jung
15
+ - Joan Lledó
15
16
  - Olle Jonsson
16
17
  - Pierre Montelle
17
18
  - Salim Semaoune
18
19
  - Tim Willard
19
- autorequire:
20
+ - Travis Bell
20
21
  bindir: bin
21
22
  cert_chain:
22
23
  - |
@@ -48,7 +49,7 @@ cert_chain:
48
49
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
49
50
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
50
51
  -----END CERTIFICATE-----
51
- date: 2024-08-22 00:00:00.000000000 Z
52
+ date: 2025-02-28 00:00:00.000000000 Z
52
53
  dependencies:
53
54
  - !ruby/object:Gem::Dependency
54
55
  name: async
@@ -120,13 +121,10 @@ dependencies:
120
121
  - - "~>"
121
122
  - !ruby/object:Gem::Version
122
123
  version: '0.9'
123
- description:
124
- email:
125
124
  executables: []
126
125
  extensions: []
127
126
  extra_rdoc_files: []
128
127
  files:
129
- - changes.md
130
128
  - lib/async/redis.rb
131
129
  - lib/async/redis/client.rb
132
130
  - lib/async/redis/cluster_client.rb
@@ -143,13 +141,13 @@ files:
143
141
  - lib/async/redis/version.rb
144
142
  - license.md
145
143
  - readme.md
144
+ - releases.md
146
145
  homepage: https://github.com/socketry/async-redis
147
146
  licenses:
148
147
  - MIT
149
148
  metadata:
150
149
  documentation_uri: https://socketry.github.io/async-redis/
151
150
  source_code_uri: https://github.com/socketry/async-redis.git
152
- post_install_message:
153
151
  rdoc_options: []
154
152
  require_paths:
155
153
  - lib
@@ -164,8 +162,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
162
  - !ruby/object:Gem::Version
165
163
  version: '0'
166
164
  requirements: []
167
- rubygems_version: 3.5.11
168
- signing_key:
165
+ rubygems_version: 3.6.2
169
166
  specification_version: 4
170
167
  summary: A Redis client library.
171
168
  test_files: []
metadata.gz.sig CHANGED
Binary file