Skip to content

Commit 18d2ace

Browse files
committed
Do not retry requests that have been dropped by the user.
valkey-io/valkey-glide#2138
1 parent 426bb99 commit 18d2ace

File tree

2 files changed

+47
-2
lines changed

2 files changed

+47
-2
lines changed

redis/src/cluster_async/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,9 @@ impl<C> Future for Request<C> {
835835

836836
fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context) -> Poll<Self::Output> {
837837
let mut this = self.as_mut().project();
838-
if this.request.is_none() {
838+
// If the sender is closed, the caller is no longer waiting for the reply, and it is ambiguous
839+
// whether they expect the side-effect of the request to happen or not.
840+
if this.request.is_none() || this.request.as_ref().unwrap().sender.is_closed() {
839841
return Poll::Ready(Next::Done);
840842
}
841843
let future = match this.future.as_mut().project() {

redis/tests/test_cluster_async.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ mod cluster_async {
1616
};
1717

1818
use futures::prelude::*;
19-
use futures_time::task::sleep;
19+
use futures_time::{future::FutureExt, task::sleep};
2020
use once_cell::sync::Lazy;
2121
use std::ops::Add;
2222

@@ -4142,6 +4142,49 @@ mod cluster_async {
41424142
.unwrap();
41434143
}
41444144

4145+
#[test]
4146+
fn test_async_cluster_do_not_retry_when_receiver_was_dropped() {
4147+
let name = "test_async_cluster_do_not_retry_when_receiver_was_dropped";
4148+
let cmd = cmd("FAKE_COMMAND");
4149+
let packed_cmd = cmd.get_packed_command();
4150+
let request_counter = Arc::new(AtomicU32::new(0));
4151+
let cloned_req_counter = request_counter.clone();
4152+
let MockEnv {
4153+
runtime,
4154+
async_connection: mut connection,
4155+
..
4156+
} = MockEnv::with_client_builder(
4157+
ClusterClient::builder(vec![&*format!("redis://{name}")])
4158+
.retries(5)
4159+
.retry_wait_formula(1, 1)
4160+
.min_retry_wait(2),
4161+
name,
4162+
move |received_cmd: &[u8], _| {
4163+
respond_startup(name, received_cmd)?;
4164+
4165+
if received_cmd == packed_cmd {
4166+
cloned_req_counter.fetch_add(1, Ordering::Relaxed);
4167+
return Err(Err((ErrorKind::TryAgain, "seriously, try again").into()));
4168+
}
4169+
4170+
Err(Ok(Value::Okay))
4171+
},
4172+
);
4173+
4174+
runtime.block_on(async move {
4175+
cmd.query_async::<_, Value>(&mut connection)
4176+
.timeout(futures_time::time::Duration::from_millis(1))
4177+
.await
4178+
.unwrap_err();
4179+
// we sleep here, to allow the cluster connection time to retry. We expect it won't, but without this
4180+
// sleep the test will complete before the the runtime gave the connection time to retry, which would've made the
4181+
// test pass regardless of whether the connection tries retrying or not.
4182+
sleep(Duration::from_millis(10).into()).await;
4183+
});
4184+
4185+
assert_eq!(request_counter.load(Ordering::Relaxed), 1);
4186+
}
4187+
41454188
#[cfg(feature = "tls-rustls")]
41464189
mod mtls_test {
41474190
use crate::support::mtls_test::create_cluster_client_from_cluster;

0 commit comments

Comments
 (0)