tower-fallback: switch to Box<dyn Error + Send + Sync + 'static>

Previously the code used Either for error handling, but a boxed std Error is
smaller in the happy path and more useful.
This commit is contained in:
Henry de Valence 2020-07-14 21:22:50 -07:00
parent 4be0a8edc3
commit ecda5445d5
6 changed files with 57 additions and 60 deletions

71
Cargo.lock generated
View File

@ -36,7 +36,7 @@ dependencies = [
"ident_case",
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.33",
"syn 1.0.34",
"synstructure",
]
@ -51,9 +51,9 @@ dependencies = [
[[package]]
name = "adler"
version = "0.2.2"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccc9a9dd069569f212bc4330af9f17c4afb5e8ce185e83dbb14f1349dda18b10"
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
[[package]]
name = "aho-corasick"
@ -426,7 +426,7 @@ dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"strsim 0.9.3",
"syn 1.0.33",
"syn 1.0.34",
]
[[package]]
@ -437,7 +437,7 @@ checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
dependencies = [
"darling_core",
"quote 1.0.7",
"syn 1.0.33",
"syn 1.0.34",
]
[[package]]
@ -455,7 +455,7 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
"generic-array 0.14.2",
"generic-array 0.14.3",
]
[[package]]
@ -466,7 +466,7 @@ checksum = "e6269d127174b18c665e683e23c2c55d3735fadbec4181c7c70b0450b764bfa5"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.33",
"syn 1.0.34",
]
[[package]]
@ -489,12 +489,6 @@ dependencies = [
"thiserror",
]
[[package]]
name = "either"
version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
[[package]]
name = "equihash"
version = "0.1.0"
@ -616,7 +610,7 @@ dependencies = [
"proc-macro-hack",
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.33",
"syn 1.0.34",
]
[[package]]
@ -683,9 +677,9 @@ dependencies = [
[[package]]
name = "generic-array"
version = "0.14.2"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac746a5f3bbfdadd6106868134545e684693d54d9d44f6e9588a7d54af0bf980"
checksum = "60fb4bb6bba52f78a471264d9a3b7d026cc0af47b22cd2cffbc0b787ca003e63"
dependencies = [
"typenum",
"version_check",
@ -725,14 +719,14 @@ checksum = "90454ce4de40b7ca6a8968b5ef367bdab48413962588d0d2b1638d60090c35d7"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.33",
"syn 1.0.34",
]
[[package]]
name = "h2"
version = "0.2.5"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79b7246d7e4b979c03fa093da39cfb3617a96bbeee6310af63991668d7e843ff"
checksum = "993f9e0baeed60001cf565546b0d3dbe6a6ad23f2bd31644a133c641eccf6d53"
dependencies = [
"bytes",
"fnv",
@ -741,10 +735,10 @@ dependencies = [
"futures-util",
"http",
"indexmap",
"log",
"slab",
"tokio",
"tokio-util 0.3.1",
"tracing",
]
[[package]]
@ -1283,7 +1277,7 @@ checksum = "6a0ffd45cf79d88737d7cc85bfd5d2894bee1139b356e616fe85dc389c61aaf7"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.33",
"syn 1.0.34",
]
[[package]]
@ -1313,7 +1307,7 @@ dependencies = [
"proc-macro-error-attr",
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.33",
"syn 1.0.34",
"version_check",
]
@ -1325,7 +1319,7 @@ checksum = "3cc9795ca17eb581285ec44936da7fc2335a3f34f2ddd13118b6f4d515435c50"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.33",
"syn 1.0.34",
"syn-mid",
"version_check",
]
@ -1529,9 +1523,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.1.56"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
name = "regex"
@ -1701,7 +1695,7 @@ checksum = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.33",
"syn 1.0.34",
]
[[package]]
@ -1847,7 +1841,7 @@ checksum = "5254766110c377a921c002ca0775d4e384ba69af951fc4329d9dd77af2c25763"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.33",
"syn 1.0.34",
]
[[package]]
@ -1883,7 +1877,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.33",
"syn 1.0.34",
]
[[package]]
@ -1905,9 +1899,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.33"
version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8d5d96e8cbb005d6959f119f773bfaebb5684296108fb32600c00cde305b2cd"
checksum = "936cae2873c940d92e697597c5eee105fb570cd5689c695806f672883653349b"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
@ -1922,7 +1916,7 @@ checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.33",
"syn 1.0.34",
]
[[package]]
@ -1933,7 +1927,7 @@ checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.33",
"syn 1.0.34",
"unicode-xid 0.2.1",
]
@ -1996,7 +1990,7 @@ checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.33",
"syn 1.0.34",
]
[[package]]
@ -2050,7 +2044,7 @@ checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.33",
"syn 1.0.34",
]
[[package]]
@ -2154,7 +2148,6 @@ dependencies = [
name = "tower-fallback"
version = "0.1.0"
dependencies = [
"either",
"futures-core",
"pin-project",
"tokio",
@ -2272,7 +2265,7 @@ checksum = "f0693bf8d6f2bf22c690fc61a9d21ac69efdbb894a17ed596b9af0f01e64b84b"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.33",
"syn 1.0.34",
]
[[package]]
@ -2347,9 +2340,9 @@ dependencies = [
[[package]]
name = "try-lock"
version = "0.2.2"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "typenum"
@ -2678,6 +2671,6 @@ checksum = "de251eec69fc7c1bc3923403d18ececb929380e016afe103da75f396704f8ca2"
dependencies = [
"proc-macro2 1.0.18",
"quote 1.0.7",
"syn 1.0.33",
"syn 1.0.34",
"synstructure",
]

View File

@ -6,7 +6,6 @@ license = "MIT"
edition = "2018"
[dependencies]
either = "1.5"
tower = "0.3"
futures-core = "0.3.5"
pin-project = "0.4.20"

View File

@ -7,11 +7,12 @@ use std::{
task::{Context, Poll},
};
use either::Either;
use futures_core::ready;
use pin_project::pin_project;
use tower::Service;
use crate::BoxedError;
/// Future that completes either with the first service's successful response, or
/// with the second service's response.
#[pin_project]
@ -19,6 +20,7 @@ pub struct ResponseFuture<S1, S2, Request>
where
S1: Service<Request>,
S2: Service<Request, Response = <S1 as Service<Request>>::Response>,
S2::Error: Into<BoxedError>,
{
#[pin]
state: ResponseState<S1, S2, Request>,
@ -29,6 +31,7 @@ enum ResponseState<S1, S2, Request>
where
S1: Service<Request>,
S2: Service<Request>,
S2::Error: Into<BoxedError>,
{
PollResponse1 {
#[pin]
@ -52,6 +55,7 @@ impl<S1, S2, Request> ResponseFuture<S1, S2, Request>
where
S1: Service<Request>,
S2: Service<Request, Response = <S1 as Service<Request>>::Response>,
S2::Error: Into<BoxedError>,
{
pub(crate) fn new(fut: S1::Future, req: Request, svc2: S2) -> Self {
ResponseFuture {
@ -64,11 +68,9 @@ impl<S1, S2, Request> Future for ResponseFuture<S1, S2, Request>
where
S1: Service<Request>,
S2: Service<Request, Response = <S1 as Service<Request>>::Response>,
S2::Error: Into<BoxedError>,
{
type Output = Result<
<S1 as Service<Request>>::Response,
Either<<S1 as Service<Request>>::Error, <S2 as Service<Request>>::Error>,
>;
type Output = Result<<S1 as Service<Request>>::Response, BoxedError>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut this = self.project();
@ -88,7 +90,7 @@ where
}
},
ResponseStateProj::PollReady2 { svc2, .. } => match ready!(svc2.poll_ready(cx)) {
Err(e) => return Poll::Ready(Err(Either::Right(e))),
Err(e) => return Poll::Ready(Err(e.into())),
Ok(()) => {
if let __ResponseStateProjectionOwned::PollReady2 { mut svc2, req } =
this.state.as_mut().project_replace(ResponseState::Tmp)
@ -102,7 +104,7 @@ where
}
},
ResponseStateProj::PollResponse2 { fut } => {
return fut.poll(cx).map_err(Either::Right)
return fut.poll(cx).map_err(Into::into)
}
ResponseStateProj::Tmp => unreachable!(),
}
@ -118,6 +120,7 @@ where
S1::Future: Debug,
S2: Debug,
S2::Future: Debug,
S2::Error: Into<BoxedError>,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ResponseFuture")
@ -134,6 +137,7 @@ where
S1::Future: Debug,
S2: Debug,
S2::Future: Debug,
S2::Error: Into<BoxedError>,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {

View File

@ -6,4 +6,5 @@ pub mod future;
mod service;
pub use self::service::Fallback;
pub use either::Either;
pub type BoxedError = Box<dyn std::error::Error + Send + Sync + 'static>;

View File

@ -1,9 +1,10 @@
use super::future::ResponseFuture;
use either::Either;
use std::task::{Context, Poll};
use tower::Service;
use super::future::ResponseFuture;
use crate::BoxedError;
/// Provides fallback processing on a second service if the first service returned an error.
#[derive(Debug)]
pub struct Fallback<S1, S2>
@ -36,15 +37,17 @@ impl<S1, S2, Request> Service<Request> for Fallback<S1, S2>
where
S1: Service<Request>,
S2: Service<Request, Response = <S1 as Service<Request>>::Response>,
S1::Error: Into<BoxedError>,
S2::Error: Into<BoxedError>,
S2: Clone,
Request: Clone,
{
type Response = <S1 as Service<Request>>::Response;
type Error = Either<<S1 as Service<Request>>::Error, <S2 as Service<Request>>::Error>;
type Error = BoxedError;
type Future = ResponseFuture<S1, S2, Request>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.svc1.poll_ready(cx).map_err(Either::Left)
self.svc1.poll_ready(cx).map_err(Into::into)
}
fn call(&mut self, request: Request) -> Self::Future {

View File

@ -1,5 +1,5 @@
use tower::{service_fn, Service, ServiceExt};
use tower_fallback::{Either, Fallback};
use tower_fallback::Fallback;
#[tokio::test]
async fn fallback() {
@ -24,10 +24,7 @@ async fn fallback() {
let mut svc = Fallback::new(svc1, svc2);
assert_eq!(svc.ready_and().await.unwrap().call(1).await, Ok(1));
assert_eq!(svc.ready_and().await.unwrap().call(11).await, Ok(111));
assert_eq!(
svc.ready_and().await.unwrap().call(21).await,
Err(Either::Right("too big value on svc2"))
);
assert_eq!(svc.ready_and().await.unwrap().call(1).await.unwrap(), 1);
assert_eq!(svc.ready_and().await.unwrap().call(11).await.unwrap(), 111);
assert!(svc.ready_and().await.unwrap().call(21).await.is_err());
}