Control pip timeout duration via environment variable (#1694)

<!--
Thank you for contributing to uv! To help us out with reviewing, please
consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->

## Summary

Add the environment variable `UV_REQUEST_TIMEOUT` to allow control over
pip timeouts.

Closes #1549 

## Test Plan

I built uv in the repository top Dockerfile, set the timeout to 3
seconds, and ran `uv pip install torch`.
I measured the execution time with the time command and confirmed that
the process finished at a value close to the timeout we set.

```bash
root@037c69228cdc:~# time UV_REQUEST_TIMEOUT=3 /uv pip install torch
Resolved 22 packages in 25ms
error: Failed to download distributions
  Caused by: Failed to fetch wheel: nvidia-cusolver-cu12==11.4.5.107
  Caused by: Failed to extract source distribution
  Caused by: request or response body error: operation timed out
  Caused by: operation timed out

real    0m3.064s
user    0m0.225s
sys     0m0.240s
```
This commit is contained in:
Di-Is 2024-02-20 13:37:56 +09:00 committed by GitHub
parent 692c00defe
commit 36edaeecf2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 18 additions and 2 deletions

1
Cargo.lock generated
View file

@ -4317,6 +4317,7 @@ dependencies = [
"uv-cache",
"uv-fs",
"uv-normalize",
"uv-warnings",
]
[[package]]

View file

@ -14,6 +14,7 @@ platform-tags = { path = "../platform-tags" }
uv-cache = { path = "../uv-cache" }
uv-fs = { path = "../uv-fs", features = ["tokio"] }
uv-normalize = { path = "../uv-normalize" }
uv-warnings = { path = "../uv-warnings" }
pypi-types = { path = "../pypi-types" }
async-trait = { workspace = true }

View file

@ -1,4 +1,5 @@
use std::collections::BTreeMap;
use std::env;
use std::fmt::Debug;
use std::path::Path;
use std::str::FromStr;
@ -13,7 +14,7 @@ use serde::{Deserialize, Serialize};
use tempfile::tempfile_in;
use tokio::io::BufWriter;
use tokio_util::compat::FuturesAsyncReadCompatExt;
use tracing::{info_span, instrument, trace, warn, Instrument};
use tracing::{debug, info_span, instrument, trace, warn, Instrument};
use url::Url;
use distribution_filename::{DistFilename, SourceDistFilename, WheelFilename};
@ -23,6 +24,7 @@ use pep440_rs::Version;
use pypi_types::{Metadata21, SimpleJson};
use uv_cache::{Cache, CacheBucket, WheelCache};
use uv_normalize::PackageName;
use uv_warnings::warn_user_once;
use crate::cached_client::CacheControl;
use crate::html::SimpleHtml;
@ -78,11 +80,23 @@ impl RegistryClientBuilder {
pub fn build(self) -> RegistryClient {
let client_raw = {
// Get pip timeout from env var
let default_timeout = 5 * 60;
let timeout = env::var("UV_REQUEST_TIMEOUT")
.map_err(|_| default_timeout)
.and_then(|value| {
value.parse::<u64>()
.map_err(|_| {
warn_user_once!("Ignoring invalid value for UV_REQUEST_TIMEOUT. Expected integer number of seconds, got {value}.");
default_timeout
})
}).unwrap_or(default_timeout);
debug!("Using registry request timeout of {}s", timeout);
// Disallow any connections.
let client_core = ClientBuilder::new()
.user_agent("uv")
.pool_max_idle_per_host(20)
.timeout(std::time::Duration::from_secs(60 * 5));
.timeout(std::time::Duration::from_secs(timeout));
client_core.build().expect("Failed to build HTTP client.")
};