Skip to content

Commit 5a6018b

Browse files
authored
fix(volo-thrift): clean waiters while failed waiting for idle connection (#547)
1 parent 7d9814d commit 5a6018b

File tree

3 files changed

+53
-4
lines changed

3 files changed

+53
-4
lines changed

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

volo-thrift/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "volo-thrift"
3-
version = "0.10.5"
3+
version = "0.10.6"
44
edition.workspace = true
55
homepage.workspace = true
66
repository.workspace = true

volo-thrift/src/transport/pool/mod.rs

+51-2
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,17 @@ impl<K: Key, T: Poolable + Send + 'static> Pool<K, T> {
208208
})
209209
}
210210

211+
/// Returns a `Checkout` which is a future that resolves if an idle
212+
/// connection becomes available.
213+
pub fn checkout(&self, key: K, waiter: (oneshot::Receiver<T>, usize)) -> Checkout<K, T> {
214+
Checkout {
215+
key,
216+
pool: self.clone(),
217+
waiter,
218+
clean: true,
219+
}
220+
}
221+
211222
pub async fn get<MT>(
212223
&self,
213224
key: K,
@@ -219,7 +230,7 @@ impl<K: Key, T: Poolable + Send + 'static> Pool<K, T> {
219230
MT: UnaryService<K, Response = T> + Send + 'static + Sync,
220231
MT::Error: Into<crate::ClientError> + Send,
221232
{
222-
let (rx, _waiter_token) = {
233+
let (rx, waiter_token) = {
223234
let entry = 'outer: loop {
224235
let entry = 'inner: {
225236
let mut inner = self.inner.lock().volo_unwrap();
@@ -286,6 +297,7 @@ impl<K: Key, T: Poolable + Send + 'static> Pool<K, T> {
286297
};
287298

288299
// 3. select waiter and mc return future
300+
let checkout = self.checkout(key.clone(), (rx, waiter_token));
289301
let connector = {
290302
let key = key.clone();
291303
let this = self.clone();
@@ -309,7 +321,7 @@ impl<K: Key, T: Poolable + Send + 'static> Pool<K, T> {
309321
};
310322

311323
// waiter or make transport finished
312-
match future::select(rx, started::lazy(connector)).await {
324+
match future::select(checkout, started::lazy(connector)).await {
313325
Either::Left((Ok(v), fut)) => {
314326
// check the make transport future has started
315327
if fut.started() {
@@ -407,6 +419,43 @@ impl<K: Key, T: Poolable> Drop for Connecting<K, T> {
407419
}
408420
}
409421

422+
pub struct Checkout<K: Key, T: Poolable> {
423+
key: K,
424+
pool: Pool<K, T>,
425+
waiter: (oneshot::Receiver<T>, usize),
426+
clean: bool,
427+
}
428+
429+
impl<K: Key, T: Poolable> Future for Checkout<K, T> {
430+
type Output = Result<T, oneshot::error::RecvError>;
431+
432+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
433+
match Pin::new(&mut self.waiter.0).poll(cx) {
434+
Poll::Ready(v) => {
435+
// Successfully received an idle connection, it means that the corresponding tx is
436+
// already popped from waiters, so no need to remove it again.
437+
self.clean = false;
438+
Poll::Ready(v)
439+
}
440+
Poll::Pending => Poll::Pending,
441+
}
442+
}
443+
}
444+
445+
impl<K: Key, T: Poolable> Drop for Checkout<K, T> {
446+
fn drop(&mut self) {
447+
// if clean needed, remove the corresponding tx from waiters
448+
if self.clean {
449+
tracing::trace!("checkout dropped for {:?}", self.key);
450+
if let Ok(mut pool) = self.pool.inner.lock() {
451+
if let Some(waiters) = pool.waiters.get_mut(&self.key) {
452+
waiters.remove(self.waiter.1);
453+
}
454+
}
455+
}
456+
}
457+
}
458+
410459
struct Idle<T> {
411460
inner: T,
412461
idle_at: Instant,

0 commit comments

Comments
 (0)