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
This commit is contained in:
David Pedersen
2021-05-07 09:45:35 +02:00
committed by GitHub
parent 4b26e78109
commit 4a917a32f0
2 changed files with 15 additions and 5 deletions
+7 -2
View File
@@ -56,12 +56,17 @@ mod service {
} }
fn call(&mut self, req: Request<BoxBody>) -> Self::Future { fn call(&mut self, req: Request<BoxBody>) -> 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 { Box::pin(async move {
// Do extra async work here... // Do extra async work here...
let response = inner.call(req).await?;
channel.call(req).await.map_err(Into::into) Ok(response)
}) })
} }
} }
+8 -3
View File
@@ -71,12 +71,17 @@ where
} }
fn call(&mut self, req: HyperRequest<Body>) -> Self::Future { fn call(&mut self, req: HyperRequest<Body>) -> 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 { 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)
}) })
} }
} }