hjr3 / hyper-timeout

A timeout connector for the hyper client
Other
25 stars 12 forks source link

Example for how to catch timeout error #28

Closed qu1ck closed 5 months ago

qu1ck commented 5 months ago

I'm on hyper 0.14 and hyper-timeout 0.4.1 I'm trying to do a simple proxy client and my code looks like this

                    let mut connector = TimeoutConnector::new(HttpsConnector::new());
                    connector.set_connect_timeout(Some(Duration::from_secs(5)));
                    connector.set_read_timeout(Some(Duration::from_secs(5)));
                    connector.set_write_timeout(Some(Duration::from_secs(5)));
                    let client = Client::builder().build::<_, hyper::Body>(connector);

                    match client.request(req).await {
                        Ok(mut response) => {
                            // pass the response up
                            Ok(response)
                        }
                        Err(e) => {
                            println!("{:?}", e);
                            if e.is_timeout() {
                                println!("Request timed out");
                                // Generate a 408 response
                                Ok(timed_out())
                            } else {
                                // pass other errors as is
                                Err(e)
                            }
                        },
                    }

I expect that all timeout errors would be caught and it would return a 408 response but if timeout happens in connection then is_timeout() does not work. This is printed in stdout in such case: hyper::Error(Connect, Custom { kind: TimedOut, error: Elapsed(()) })

I'm not very good with rust but I think it's because hyper-timeout uses io::Error::TimedOut instead of hyper::Error so hyper code can not infer the kind of the cause of the error correctly.

Am I missing something? Is there a better way to detect timeout errors?

hjr3 commented 5 months ago

I think it's because hyper-timeout uses io::Error::TimedOut

Yes, we do that here. https://github.com/hjr3/hyper-timeout/blob/master/src/lib.rs#L82C38-L82C80

You can match on the error kind. See https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=dafc7ac2b96522216f3af52b4c76de7f

qu1ck commented 5 months ago

Thanks, for posterity in my case full check ended up looking like this

    if e.is_timeout()
        || e.source().is_some_and(|s| {
            s.downcast_ref::<io::Error>()
                .is_some_and(|s| s.kind() == io::ErrorKind::TimedOut)
        })
    {
        println!("Request timed out");
        Ok(timed_out())
    }