refactor(client): change retryable request future from boxed to 'impl Future'
This commit is contained in:
@@ -247,25 +247,45 @@ where C: Connect + Sync + 'static,
|
||||
}
|
||||
|
||||
|
||||
let client = self.clone();
|
||||
let uri = req.uri().clone();
|
||||
let pool_key = (Arc::new(domain.to_string()), self.ver);
|
||||
let fut = RetryableSendRequest {
|
||||
client,
|
||||
future: self.send_request(req, pool_key.clone()),
|
||||
pool_key,
|
||||
uri,
|
||||
};
|
||||
ResponseFuture::new(Box::new(fut))
|
||||
ResponseFuture::new(Box::new(self.retryably_send_request(req, pool_key)))
|
||||
}
|
||||
|
||||
//TODO: replace with `impl Future` when stable
|
||||
fn send_request(&self, mut req: Request<B>, pool_key: PoolKey) -> Box<Future<Item=Response<Body>, Error=ClientError<B>> + Send> {
|
||||
fn retryably_send_request(&self, req: Request<B>, pool_key: PoolKey) -> impl Future<Item=Response<Body>, Error=::Error> {
|
||||
let client = self.clone();
|
||||
let uri = req.uri().clone();
|
||||
|
||||
let mut send_fut = client.send_request(req, pool_key.clone());
|
||||
future::poll_fn(move || loop {
|
||||
match send_fut.poll() {
|
||||
Ok(Async::Ready(resp)) => return Ok(Async::Ready(resp)),
|
||||
Ok(Async::NotReady) => return Ok(Async::NotReady),
|
||||
Err(ClientError::Normal(err)) => return Err(err),
|
||||
Err(ClientError::Canceled {
|
||||
connection_reused,
|
||||
mut req,
|
||||
reason,
|
||||
}) => {
|
||||
if !client.retry_canceled_requests || !connection_reused {
|
||||
// if client disabled, don't retry
|
||||
// a fresh connection means we definitely can't retry
|
||||
return Err(reason);
|
||||
}
|
||||
|
||||
trace!("unstarted request canceled, trying again (reason={:?})", reason);
|
||||
*req.uri_mut() = uri.clone();
|
||||
send_fut = client.send_request(req, pool_key.clone());
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn send_request(&self, mut req: Request<B>, pool_key: PoolKey) -> impl Future<Item=Response<Body>, Error=ClientError<B>> {
|
||||
let race = self.pool_checkout_or_connect(req.uri().clone(), pool_key);
|
||||
|
||||
let ver = self.ver;
|
||||
let executor = self.executor.clone();
|
||||
Box::new(race.and_then(move |mut pooled| {
|
||||
race.and_then(move |mut pooled| {
|
||||
if ver == Ver::Http1 {
|
||||
// CONNECT always sends origin-form, so check it first...
|
||||
if req.method() == &Method::CONNECT {
|
||||
@@ -342,7 +362,7 @@ where C: Connect + Sync + 'static,
|
||||
}
|
||||
Ok(res)
|
||||
}))
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
fn pool_checkout_or_connect(&self, uri: Uri, pool_key: PoolKey)
|
||||
@@ -529,55 +549,6 @@ impl Future for ResponseFuture {
|
||||
}
|
||||
}
|
||||
|
||||
struct RetryableSendRequest<C, B> {
|
||||
client: Client<C, B>,
|
||||
future: Box<Future<Item=Response<Body>, Error=ClientError<B>> + Send>,
|
||||
pool_key: PoolKey,
|
||||
uri: Uri,
|
||||
}
|
||||
|
||||
impl<C, B> fmt::Debug for RetryableSendRequest<C, B> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.pad("Future<Response>")
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, B> Future for RetryableSendRequest<C, B>
|
||||
where
|
||||
C: Connect + 'static,
|
||||
C::Future: 'static,
|
||||
B: Payload + Send + 'static,
|
||||
B::Data: Send,
|
||||
{
|
||||
type Item = Response<Body>;
|
||||
type Error = ::Error;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
loop {
|
||||
match self.future.poll() {
|
||||
Ok(Async::Ready(resp)) => return Ok(Async::Ready(resp)),
|
||||
Ok(Async::NotReady) => return Ok(Async::NotReady),
|
||||
Err(ClientError::Normal(err)) => return Err(err),
|
||||
Err(ClientError::Canceled {
|
||||
connection_reused,
|
||||
mut req,
|
||||
reason,
|
||||
}) => {
|
||||
if !self.client.retry_canceled_requests || !connection_reused {
|
||||
// if client disabled, don't retry
|
||||
// a fresh connection means we definitely can't retry
|
||||
return Err(reason);
|
||||
}
|
||||
|
||||
trace!("unstarted request canceled, trying again (reason={:?})", reason);
|
||||
*req.uri_mut() = self.uri.clone();
|
||||
self.future = self.client.send_request(req, self.pool_key.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: allow() required due to `impl Trait` leaking types to this lint
|
||||
#[allow(missing_debug_implementations)]
|
||||
struct PoolClient<B> {
|
||||
@@ -614,14 +585,14 @@ impl<B> PoolClient<B> {
|
||||
}
|
||||
|
||||
impl<B: Payload + 'static> PoolClient<B> {
|
||||
fn send_request_retryable(&mut self, req: Request<B>) -> impl_trait!(ty: Future<Item = Response<Body>, Error = (::Error, Option<Request<B>>)> + Send)
|
||||
fn send_request_retryable(&mut self, req: Request<B>) -> impl Future<Item = Response<Body>, Error = (::Error, Option<Request<B>>)>
|
||||
where
|
||||
B: Send,
|
||||
{
|
||||
impl_trait!(e: match self.tx {
|
||||
match self.tx {
|
||||
PoolTx::Http1(ref mut tx) => Either::A(tx.send_request_retryable(req)),
|
||||
PoolTx::Http2(ref mut tx) => Either::B(tx.send_request_retryable(req)),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user