Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add connect, read, and write timeouts to client #1234

Open
sfackler opened this issue Jun 25, 2017 · 26 comments
Open

Add connect, read, and write timeouts to client #1234

sfackler opened this issue Jun 25, 2017 · 26 comments
Labels
A-client Area: client. B-rfc Blocked: More comments would be useful in determine next steps. C-feature Category: feature. This is adding a new feature.

Comments

@sfackler
Copy link
Contributor

No description provided.

@hjr3
Copy link
Contributor

hjr3 commented Jul 3, 2017

I am going to try get a PR up for this. There are two options for timers, but I am unsure of which is best for hyper. The tokio_timer crate is more accurate but uses a dedicated thread. The Timeout in tokio-core is less accurate but does not require the extra thread.

If I was making the decision, I would create a single tokio-timer Timer (1 dedicated thread), configure it properly and then use that for any timeout needs. Does anyone else have any opinions?

@seanmonstar
Copy link
Member

hyper 0.11 didn't ship with these for a couple reasons:

  • It's possible to have a rough overall timeout by using timeouts outside of hyper.
  • I didn't want to pick a timer implementation that was different than the user, and then end up that multiple timer implementations were running.

Still, I realize it would be useful to have these in hyper, so let's explore!

  • For anyone wanting it immediately, you can largely get most of it working externally. A "connect" timeout can be used by providing a custom Connect that wraps the HttpConnector and a Timeout. A "write" timeout (for a body) can be sort of hacked in by providing a custom Body stream. And a "read" timeout could be used by selecting on the FutureResponse, and/or the response body. I realize it's not super accurate, but it's there for the urgent.
  • For the implementation in hyper, unless there the coarser timeouts are bad (it shouldn't be seconds off, just perhaps a few milliseconds if the timer isn't quite reached, and another loop of the Core would take a few milliseconds to get back), I'm leaning towards using tokio-core timeouts. They're lighter weight, doesn't start a new thread, and doesn't require another dependency.

@sfackler
Copy link
Contributor Author

sfackler commented Jul 3, 2017

I wrote up a little crate handling read and write timeouts via the standard tokio-core timer: https://crates.io/crates/tokio-io-timeout

@nielsle
Copy link

nielsle commented Jul 4, 2017

Withoutboats has a pull request that adds middleware wrappers to tokio_service::Service. Perhaps that could be used to add logging and timing and retries to the hyper::Client

tokio-rs/tokio-service#21

This solution would be fairly generic and extendable, but it might also be slightly complicated.

@seanmonstar seanmonstar added the A-client Area: client. label Jul 4, 2017
@hjr3
Copy link
Contributor

hjr3 commented Jul 7, 2017

Based on the discussion, I wrote a TimeoutConnector that wraps an existing Connect implementation here https://github.com/hyperium/hyper/compare/master...hjr3:issue-1234?expand=1. I left the code in the connect.rs file for now, so as not to deal with module shenanigans. The TimeoutConnector can be used with the HttpsConnector in hyper_tls too. This may also get use closer to the suggestion from @nielsle about using Middleware. I say may because I did not like very closely that how the PR works. I still owe some tests.

The alternative is to embed the timeout in HttpConnector too, but the wrapper seemed better/cleaner.

I will start playing around with the crate from @sfackler and see if I can get read/write timeouts setup.

@skinowski
Copy link

Could you please update the 'advanced' client example with an overall timeout? This is the general case and if it's in the example, it'll be super helpful.

@hjr3
Copy link
Contributor

hjr3 commented Jul 8, 2017

@skinowski Definitely. Where is the advanced example? I only see the simple example.

@skinowski
Copy link

@hjr3 Here: https://hyper.rs/guides/client/advanced/

I've also figured how to do this myself:

let dur = Duration::from_millis(1000);
let work = client.get(...).and_then(...)....;
let tm = timer.timeout(work, dur);

But it's really easy to get caught in wrapped types of these futures: map, and_then, map_err, select2, join, etc. are not easy to follow for a beginner.

@hjr3
Copy link
Contributor

hjr3 commented Jul 8, 2017

I have read/write timeouts in place. After putting those in, it seems natural to want to configure the client with a connect_timeout instead of wrapping the Connect implementation. I am trying to figure out how to do that.

hjr3 added a commit to hjr3/hyper that referenced this issue Jul 12, 2017
- Add a `TimeoutConnector` implememtation that can be used to wrap any
  implemention of `Connect`.
- Add read and write timeout support to `Client` and client `Config`.
  The internal client implementation now wraps I/O with the
  tokio-io-timeout crate. Due to the way tokio-proto works, the user
  will see a "broken pipe" error instead of a "timed out" error when
  a read or write timeout occurs.

Closes hyperium#1234
@hjr3
Copy link
Contributor

hjr3 commented Jul 14, 2017

@skinowski I also added a PR to add the general timeout to the guide hyperium/hyperium.github.io#13

@hjr3
Copy link
Contributor

hjr3 commented Jul 18, 2017

I created https://crates.io/crates/hyper-timeout to get connect, read and write timeout functionality. So far, it has been working for my use case. There may be some changes required to tokio-io-timeout, including this comment from @seanmonstar:

As a side note, looking at the tokio-io-timeout crate, the implementations of AsyncRead and AsyncWrite don't pass forward the read_buf and write_buf methods, which would mean readv and writev are no longer used for TcpStream.

I will see about getting some PRs up for tokio-io-timeout.

@sfackler
Copy link
Contributor Author

I've added implementations of read_buf and write_buf.

@hjr3
Copy link
Contributor

hjr3 commented Jul 24, 2017

@sfackler 👍 i will update my crate. edit: nevermind, this is a library. though i did notice i committed the Cargo.lock, which i fixed.

@softprops
Copy link
Contributor

I was just going to open an issue about server side read write timeouts. Would any of the potential solutions above also cover servers?

@sfackler
Copy link
Contributor Author

@softprops the tokio-io-timeout crate can handle them if you manage the server accept loop manually. Example: https://github.com/sfackler/foo/blob/master/src/main.rs#L53

@softprops
Copy link
Contributor

softprops commented Sep 25, 2017

Nice. What are the chances of something like this landing in hyper itself?

@seanmonstar
Copy link
Member

The current situation of timers in tokio are in flux, so I have been wanting to wait for the dust there to settle.

@softprops
Copy link
Contributor

Makes sense

@seanmonstar seanmonstar added B-rfc Blocked: More comments would be useful in determine next steps. C-feature Category: feature. This is adding a new feature. labels Oct 18, 2018
@cetra3
Copy link

cetra3 commented Aug 8, 2019

Is there still plans to add read/write timeouts to client requests? I understand you can use tokio's timeout function to timeout the request overall, but this is sometimes not what you want.

Sometimes a download can be slow as heck, but it's still downloading, so as long as the time between delivery of bytes is not hit, then it's an "active" connection.

@hjr3
Copy link
Contributor

hjr3 commented Aug 9, 2019

@cetra3 Hi, you can look at using https://crates.io/crates/hyper-timeout. I just updated it to work with hyper v0.12.

@cetra3
Copy link

cetra3 commented Aug 12, 2019

Cheers @hjr3, I'm assuming this is compatible with the https connector?

@hjr3
Copy link
Contributor

hjr3 commented Aug 12, 2019 via email

@chewi
Copy link
Contributor

chewi commented Sep 26, 2019

We've been using hyper-timeout for a little while but it has one major drawback that only an implementation within hyper can provide. If the requested host name resolves to multiple IP addresses, hyper internally tries to connect to each one in turn. If one of them doesn't respond at all then it hangs until the OS-level timeout kicks in. This defaults to 127 seconds on Linux due to tcp_syn_retries being 6. hyper-timeout wraps around all the connection attempts rather than each one individually so setting that timeout to something shorter means that it will give up before trying the second address. You could reduce tcp_syn_retries but this is kernel-wide so this is far from ideal.

@let4be
Copy link

let4be commented May 1, 2021

Is there any update on this?...
fine grained control of timeout(including connecting to several IPs as mentioned by @chewi) would be really nice to have

@chewi
Copy link
Contributor

chewi commented May 1, 2021

Yes, Hyper supports this natively now. It was added in Hyper 13 and I backported it to 12.

@EdorianDark
Copy link

It it is supported, why is this issue not closed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-client Area: client. B-rfc Blocked: More comments would be useful in determine next steps. C-feature Category: feature. This is adding a new feature.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants