Skip to content

Commit a70078d

Browse files
committed
Add RESP3 support to cluster connections.
1 parent 63011d6 commit a70078d

File tree

6 files changed

+101
-1
lines changed

6 files changed

+101
-1
lines changed

redis/src/cluster.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,7 @@ pub(crate) fn get_connection_info(
910910
redis: RedisConnectionInfo {
911911
password: cluster_params.password,
912912
username: cluster_params.username,
913+
use_resp3: cluster_params.use_resp3,
913914
..Default::default()
914915
},
915916
})

redis/src/cluster_client.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ struct BuilderParams {
3333
retries_configuration: RetryParams,
3434
connection_timeout: Option<Duration>,
3535
topology_checks_interval: Option<Duration>,
36+
use_resp3: bool,
3637
}
3738

3839
#[derive(Clone)]
@@ -86,6 +87,7 @@ pub(crate) struct ClusterParams {
8687
pub(crate) connection_timeout: Duration,
8788
pub(crate) topology_checks_interval: Option<Duration>,
8889
pub(crate) tls_params: Option<TlsConnParams>,
90+
pub(crate) use_resp3: bool,
8991
}
9092

9193
impl ClusterParams {
@@ -109,6 +111,7 @@ impl ClusterParams {
109111
connection_timeout: value.connection_timeout.unwrap_or(Duration::MAX),
110112
topology_checks_interval: value.topology_checks_interval,
111113
tls_params,
114+
use_resp3: value.use_resp3,
112115
})
113116
}
114117
}
@@ -315,6 +318,15 @@ impl ClusterClientBuilder {
315318
self
316319
}
317320

321+
/// Sets whether the new ClusterClient should connect to the servers using RESP3.
322+
///
323+
/// If not set, the default is to use RESP3.
324+
#[cfg(any(feature = "tls-native-tls", feature = "tls-rustls"))]
325+
pub fn use_resp3(mut self, use_resp3: bool) -> ClusterClientBuilder {
326+
self.builder_params.use_resp3 = use_resp3;
327+
self
328+
}
329+
318330
/// Use `build()`.
319331
#[deprecated(since = "0.22.0", note = "Use build()")]
320332
pub fn open(self) -> RedisResult<ClusterClient> {

redis/tests/support/cluster.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use tempfile::TempDir;
1616

1717
use crate::support::{build_keys_and_certs_for_tls, Module};
1818

19+
use super::use_resp3;
1920
#[cfg(feature = "tls-rustls")]
2021
use super::{build_single_client, load_certs_from_file};
2122

@@ -343,6 +344,7 @@ impl TestClusterContext {
343344
.map(RedisServer::connection_info)
344345
.collect();
345346
let mut builder = redis::cluster::ClusterClientBuilder::new(initial_nodes.clone());
347+
builder = builder.use_resp3(use_resp3());
346348

347349
#[cfg(feature = "tls-rustls")]
348350
if mtls_enabled {

redis/tests/support/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use redis::{ClientTlsConfig, TlsCertificates};
2020
use socket2::{Domain, Socket, Type};
2121
use tempfile::TempDir;
2222

23-
fn use_resp3() -> bool {
23+
pub fn use_resp3() -> bool {
2424
env::var("RESP3").unwrap_or_default() == "true"
2525
}
2626

redis/tests/test_cluster.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,45 @@ fn test_cluster_multi_shard_commands() {
136136
assert_eq!(res, vec!["bazz", "bar", "foo"]);
137137
}
138138

139+
#[test]
140+
fn test_cluster_resp3() {
141+
if !use_resp3() {
142+
return;
143+
}
144+
let cluster = TestClusterContext::new(3, 0);
145+
146+
let mut connection = cluster.connection();
147+
148+
let _: () = redis::cmd("HSET")
149+
.arg("hash")
150+
.arg("foo")
151+
.arg("baz")
152+
.execute(&mut connection);
153+
let _: () = redis::cmd("HSET")
154+
.arg("hash")
155+
.arg("bar")
156+
.arg("foobar")
157+
.execute(&mut connection);
158+
let result: Value = redis::cmd("HGETALL")
159+
.arg("hash")
160+
.query(&mut connection)
161+
.unwrap();
162+
163+
assert_eq!(
164+
result,
165+
Value::Map(vec![
166+
(
167+
Value::BulkString("foo".as_bytes().to_vec()),
168+
Value::BulkString("baz".as_bytes().to_vec())
169+
),
170+
(
171+
Value::BulkString("bar".as_bytes().to_vec()),
172+
Value::BulkString("foobar".as_bytes().to_vec())
173+
)
174+
])
175+
);
176+
}
177+
139178
#[test]
140179
#[cfg(feature = "script")]
141180
fn test_cluster_script() {

redis/tests/test_cluster_async.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,52 @@ fn test_async_cluster_route_info_to_nodes() {
203203
.unwrap();
204204
}
205205

206+
#[test]
207+
fn test_cluster_resp3() {
208+
if !use_resp3() {
209+
return;
210+
}
211+
block_on_all(async move {
212+
let cluster = TestClusterContext::new(3, 0);
213+
214+
let mut connection = cluster.async_connection().await;
215+
216+
let _: () = redis::cmd("HSET")
217+
.arg("hash")
218+
.arg("foo")
219+
.arg("baz")
220+
.query_async(&mut connection)
221+
.await
222+
.unwrap();
223+
let _: () = redis::cmd("HSET")
224+
.arg("hash")
225+
.arg("bar")
226+
.arg("foobar")
227+
.query_async(&mut connection)
228+
.await
229+
.unwrap();
230+
let result: Value = redis::cmd("HGETALL")
231+
.arg("hash")
232+
.query_async(&mut connection)
233+
.await
234+
.unwrap();
235+
236+
assert_eq!(
237+
result,
238+
Value::Map(vec![
239+
(
240+
Value::BulkString("foo".as_bytes().to_vec()),
241+
Value::BulkString("baz".as_bytes().to_vec())
242+
),
243+
(
244+
Value::BulkString("bar".as_bytes().to_vec()),
245+
Value::BulkString("foobar".as_bytes().to_vec())
246+
)
247+
])
248+
);
249+
});
250+
}
251+
206252
#[ignore] // TODO Handle pipe where the keys do not all go to the same node
207253
#[test]
208254
fn test_async_cluster_basic_pipe() {

0 commit comments

Comments
 (0)