Search code examples
httprusttimeouthyperrust-tokio

How to set timeout for HTTP request with hyper, tokio and futures in Rust?


How do I set a timeout for HTTP request using asynchronous Hyper (>= 0.11)?

Here is the example of the code without timeout:

extern crate hyper;
extern crate tokio_core;
extern crate futures;

use futures::Future;
use hyper::Client;
use tokio_core::reactor::Core;

fn main() {
    let mut core = Core::new().unwrap();
    let client = Client::new(&core.handle());

    let uri = "http://stackoverflow.com".parse().unwrap();
    let work = client.get(uri).map(|res| {
        res.status()
    });

    match core.run(work) {
        Ok(status) => println!("Status: {}", status),
        Err(e) => println!("Error: {:?}", e)
    }
}

Solution

  • Answering my own question with a working code example, based on the link provided by seanmonstar to the Hyper Guide / General Timeout:

    extern crate hyper;
    extern crate tokio_core;
    extern crate futures;
    
    use futures::Future;
    use futures::future::Either;
    use hyper::Client;
    use tokio_core::reactor::Core;
    use std::time::Duration;
    use std::io;
    
    fn main() {
        let mut core = Core::new().unwrap();
        let handle = core.handle();
        let client = Client::new(&handle);
    
        let uri: hyper::Uri = "http://stackoverflow.com".parse().unwrap();
        let request = client.get(uri.clone()).map(|res| res.status());
    
        let timeout = tokio_core::reactor::Timeout::new(Duration::from_millis(170), &handle).unwrap();
    
        let work = request.select2(timeout).then(|res| match res {
            Ok(Either::A((got, _timeout))) => Ok(got),
            Ok(Either::B((_timeout_error, _get))) => {
                Err(hyper::Error::Io(io::Error::new(
                    io::ErrorKind::TimedOut,
                    "Client timed out while connecting",
                )))
            }
            Err(Either::A((get_error, _timeout))) => Err(get_error),
            Err(Either::B((timeout_error, _get))) => Err(From::from(timeout_error)),
        });
    
        match core.run(work) {
            Ok(status) => println!("OK: {:?}", status),
            Err(e) => println!("Error: {:?}", e)
        }
    }