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

os_errno() not always reporting error 110 for connection timeouts #565

Open
bpevandro opened this issue Jul 20, 2024 · 0 comments
Open

os_errno() not always reporting error 110 for connection timeouts #565

bpevandro opened this issue Jul 20, 2024 · 0 comments

Comments

@bpevandro
Copy link

bpevandro commented Jul 20, 2024

Problem description

The below code creates one easy handle per endpoint and adds it to a multi handle to be performed asynchronously.
The endpoints vector contains a list of AWS ELBs which are associated with security groups that do not allow HTTP traffic. Therefore connections are timing out 100% of the time. However, as per the output below, os_errno() is sometimes reporting the expected error, 110, and sometimes reporting 0, indicating no issue with the connection.

use std::time::Duration;

use curl::{easy::{Easy2, Handler, WriteError}, multi::Multi};
use futures::future::join_all;
use tokio::time::sleep;

pub struct Collector(pub Vec<u8>);

impl Handler for Collector {
    fn write(&mut self, data: &[u8]) -> Result<usize, WriteError> {
        self.0.extend_from_slice(data);
        Ok(data.len())
    }
}

#[tokio::main(worker_threads = 1)]
async fn main() {
    let endpoints = vec![
        "xxx.com",
        "yyy.com",
        "zzz.com",
        ];

    let mut f = vec![];

    let mut handles = vec![];
    
    for i in 0..50 {
        let mut multi = Multi::new();
        multi.pipelining(false, false).unwrap();

        for &endpoint in &endpoints {
            println!("{}", endpoint);
            let mut handle = Easy2::new(Collector(Vec::new()));

            handle
                .connect_timeout(Duration::from_secs(2))
                .unwrap();
            handle.timeout(Duration::from_secs(5)).unwrap();
            handle.url(endpoint).unwrap();
            handle.forbid_reuse(true).unwrap();

            let handle = multi.add2(handle).unwrap();
            handles.push(handle);
        }

        f.push(send_requests(multi));
    }
 
    join_all(f).await;

    for mut handle in handles {
        println!("{:?}", handle.total_time());
        println!("{:?}", handle.os_errno());
    }
}

async fn send_requests(multi: Multi) {
    while multi.perform().unwrap() > 0 {
        sleep(Duration::from_millis(0)).await;
        // OR tokio::task::yield_now().await;
    }
}

Output:

Ok(1.9992s)
Ok(110)
Ok(1.999131s)
Ok(110)
Ok(1.999063s)
Ok(110)
Ok(2.000312s)
Ok(110)
Ok(2.000253999s)
Ok(110)
Ok(2.000207s)
Ok(110)
Ok(1.999528999s)
Ok(0)
Ok(1.999442s)
Ok(0)
Ok(1.999384s)
Ok(0)
Ok(1.999322s)
Ok(0)
Ok(1.999255999s)
Ok(0)
Ok(1.999206s)
Ok(0)
Ok(1.999976s)
Ok(110)
Ok(1.999911999s)
Ok(110)
...

I'm not sure if this is an issue with the curl crate, the code itself, or an underlying issue of the OS or libcurl. Any information that can help me understand this behaviour is much appreciated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant