From 4a917a32f05c70c99d608be5ae3fc58f130ee4df Mon Sep 17 00:00:00 2001 From: David Pedersen Date: Fri, 7 May 2021 09:45:35 +0200 Subject: [PATCH] fix(examples): Fix tower examples (#624) Doing ```rust let clone = self.inner.clone(); Box::pin(async move { let response = clone.call(request).await?; Ok(response) }) ``` If `self.inner` is (or contains) a `tower::buffer::Buffer` might panic. That is because cloning a `Buffer` drops the permit that was acquired in `poll_ready`, meaning it is no longer ready and panic in `call`. The solution is to use `mem::replace` to take the ready service and pass that into the async block. Fixes https://github.com/hyperium/tonic/issues/545 --- examples/src/tower/client.rs | 9 +++++++-- examples/src/tower/server.rs | 11 ++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/examples/src/tower/client.rs b/examples/src/tower/client.rs index 1f136f2c2..aa3135dba 100644 --- a/examples/src/tower/client.rs +++ b/examples/src/tower/client.rs @@ -56,12 +56,17 @@ mod service { } fn call(&mut self, req: Request) -> Self::Future { - let mut channel = self.inner.clone(); + // This is necessary because tonic internally uses `tower::buffer::Buffer`. + // See https://github.com/tower-rs/tower/issues/547#issuecomment-767629149 + // for details on why this is necessary + let clone = self.inner.clone(); + let mut inner = std::mem::replace(&mut self.inner, clone); Box::pin(async move { // Do extra async work here... + let response = inner.call(req).await?; - channel.call(req).await.map_err(Into::into) + Ok(response) }) } } diff --git a/examples/src/tower/server.rs b/examples/src/tower/server.rs index d25097049..574b76b7f 100644 --- a/examples/src/tower/server.rs +++ b/examples/src/tower/server.rs @@ -71,12 +71,17 @@ where } fn call(&mut self, req: HyperRequest) -> Self::Future { - let mut svc = self.inner.clone(); + // This is necessary because tonic internally uses `tower::buffer::Buffer`. + // See https://github.com/tower-rs/tower/issues/547#issuecomment-767629149 + // for details on why this is necessary + let clone = self.inner.clone(); + let mut inner = std::mem::replace(&mut self.inner, clone); Box::pin(async move { - // Do async work here.... + // Do extra async work here... + let response = inner.call(req).await?; - svc.call(req).await + Ok(response) }) } }