torrust-tracker icon indicating copy to clipboard operation
torrust-tracker copied to clipboard

Tracker Checker: handle HTTP Tracker timeouts

Open josecelano opened this issue 1 year ago • 0 comments

Parent issue: https://github.com/torrust/torrust-tracker/issues/677 Relates to: https://github.com/torrust/torrust-tracker/issues/679

NOTE: Although this issue could be implemented independently I think it would be better if it's implemented after implementing https://github.com/torrust/torrust-tracker/issues/679.

You can run a Tracker Checker with:

TORRUST_CHECKER_CONFIG='{
    "udp_trackers": [],
    "http_trackers": ["http://127.0.0.1:7070"],
    "health_checks": []
}' cargo run --bin tracker_checker

The HTTP Tracker client does not have any timeout so it will wait forever.

We have to add a timeout to the HTTP client requests:

/// HTTP Tracker Client
pub struct Client {
    base_url: Url,
    reqwest: ReqwestClient,
    key: Option<Key>,
}

impl Client {
    // ...

    pub async fn announce(&self, query: &announce::Query) -> Response {
        self.get(&self.build_announce_path_and_query(query)).await
    }

    pub async fn scrape(&self, query: &scrape::Query) -> Response {
        self.get(&self.build_scrape_path_and_query(query)).await
    }

    pub async fn announce_with_header(&self, query: &Query, key: &str, value: &str) -> Response {
        self.get_with_header(&self.build_announce_path_and_query(query), key, value)
            .await
    }

    pub async fn health_check(&self) -> Response {
        self.get(&self.build_path("health_check")).await
    }

    /// # Panics
    ///
    /// This method fails if there was an error while sending request.
    pub async fn get(&self, path: &str) -> Response {
        self.reqwest.get(self.build_url(path)).send().await.unwrap()
    }

    /// # Panics
    ///
    /// This method fails if there was an error while sending request.
    pub async fn get_with_header(&self, path: &str, key: &str, value: &str) -> Response {
        self.reqwest
            .get(self.build_url(path))
            .header(key, value)
            .send()
            .await
            .unwrap()
    }

    // ...
}

You can add a timeout to all reqwest.get like this in the Health Check:

HttpClient::builder().timeout(Duration::from_secs(5)).build().unwrap();

You can force the error by adding a sleep in the handler:

async fn handle(
    tracker: &Arc<Tracker>,
    announce_request: &Announce,
    client_ip_sources: &ClientIpSources,
    maybe_key: Option<Key>,
) -> Response {
    thread::sleep(time::Duration::from_secs(7));

    let announce_data = match handle_announce(tracker, announce_request, client_ip_sources, maybe_key).await {
        Ok(announce_data) => announce_data,
        Err(error) => return error.into_response(),
    };
    build_response(announce_request, announce_data)
}

This issue should be implemented after refactoring the HTTP Tracker client to return errors instead of panicking.

josecelano avatar Feb 02 '24 15:02 josecelano