Add --maximum-resolution-timeout (#1862)

* Add --maximum-resolution-timeout

Fixed #1823

* Display default value for `--maximum-resolution-timeout` in help
This commit is contained in:
Jiahao XU 2024-08-04 12:13:18 +10:00 committed by GitHub
parent de55e465f5
commit 52f2db4f57
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 76 additions and 48 deletions

View file

@ -187,6 +187,15 @@ pub struct Args {
)] )]
pub(crate) no_discover_github_token: bool, pub(crate) no_discover_github_token: bool,
/// Maximum time each resolution (one for each possible target and each strategy), in seconds.
#[clap(
help_heading = "Overrides",
long,
env = "BINSTALL_MAXIMUM_RESOLUTION_TIMEOUT",
default_value_t = NonZeroU16::new(180).unwrap(),
)]
pub(crate) maximum_resolution_timeout: NonZeroU16,
/// This flag is now enabled by default thus a no-op. /// This flag is now enabled by default thus a no-op.
/// ///
/// By default, Binstall will install a binary as-is in the install path. /// By default, Binstall will install a binary as-is in the install path.

View file

@ -2,6 +2,7 @@ use std::{
env, fs, env, fs,
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::Arc, sync::Arc,
time::Duration,
}; };
use binstalk::{ use binstalk::{
@ -200,6 +201,10 @@ pub fn install_crates(
SignaturePolicy::IfPresent SignaturePolicy::IfPresent
}, },
disable_telemetry: args.disable_telemetry, disable_telemetry: args.disable_telemetry,
maximum_resolution_timeout: Duration::from_secs(
args.maximum_resolution_timeout.get().into(),
),
}); });
// Destruct args before any async function to reduce size of the future // Destruct args before any async function to reduce size of the future

View file

@ -40,6 +40,7 @@ tokio = { version = "1.35.0", features = [
"rt", "rt",
"process", "process",
"sync", "sync",
"time",
], default-features = false } ], default-features = false }
tracing = "0.1.39" tracing = "0.1.39"
url = { version = "2.3.1", features = ["serde"] } url = { version = "2.3.1", features = ["serde"] }

View file

@ -1,6 +1,6 @@
//! Concrete Binstall operations. //! Concrete Binstall operations.
use std::{path::PathBuf, sync::Arc}; use std::{path::PathBuf, sync::Arc, time::Duration};
use semver::VersionReq; use semver::VersionReq;
@ -56,4 +56,6 @@ pub struct Options {
pub signature_policy: SignaturePolicy, pub signature_policy: SignaturePolicy,
pub disable_telemetry: bool, pub disable_telemetry: bool,
pub maximum_resolution_timeout: Duration,
} }

View file

@ -17,7 +17,7 @@ use itertools::Itertools;
use leon::Template; use leon::Template;
use maybe_owned::MaybeOwned; use maybe_owned::MaybeOwned;
use semver::{Version, VersionReq}; use semver::{Version, VersionReq};
use tokio::task::spawn_blocking; use tokio::{task::spawn_blocking, time::timeout};
use tracing::{debug, error, info, instrument, warn}; use tracing::{debug, error, info, instrument, warn};
use url::Url; use url::Url;
@ -182,62 +182,73 @@ async fn resolve_inner(
} }
for fetcher in handles { for fetcher in handles {
match AutoAbortJoinHandle::new(fetcher.clone().find()) match timeout(
.flattened_join() opts.maximum_resolution_timeout,
.await AutoAbortJoinHandle::new(fetcher.clone().find()).flattened_join(),
)
.await
{ {
Ok(true) => { Ok(ret) => match ret {
// Generate temporary binary path Ok(true) => {
let bin_path = opts.temp_dir.join(format!( // Generate temporary binary path
"bin-{}-{}-{}", let bin_path = opts.temp_dir.join(format!(
package_info.name, "bin-{}-{}-{}",
fetcher.target(), package_info.name,
fetcher.fetcher_name() fetcher.target(),
)); fetcher.fetcher_name()
));
match download_extract_and_verify( match download_extract_and_verify(
fetcher.as_ref(), fetcher.as_ref(),
&bin_path, &bin_path,
&package_info, &package_info,
&opts.install_path, &opts.install_path,
opts.no_symlinks, opts.no_symlinks,
) )
.await .await
{ {
Ok(bin_files) => { Ok(bin_files) => {
if !bin_files.is_empty() { if !bin_files.is_empty() {
return Ok(Resolution::Fetch(Box::new(ResolutionFetch { return Ok(Resolution::Fetch(Box::new(ResolutionFetch {
fetcher, fetcher,
new_version: package_info.version, new_version: package_info.version,
name: package_info.name, name: package_info.name,
version_req: version_req_str, version_req: version_req_str,
source: package_info.source, source: package_info.source,
bin_files, bin_files,
}))); })));
} else { } else {
warn!( warn!(
"Error when checking binaries provided by fetcher {}: \ "Error when checking binaries provided by fetcher {}: \
The fetcher does not provide any optional binary", The fetcher does not provide any optional binary",
fetcher.source_name(),
);
}
}
Err(err) => {
if let BinstallError::UserAbort = err {
return Err(err);
}
warn!(
"Error while downloading and extracting from fetcher {}: {}",
fetcher.source_name(), fetcher.source_name(),
err
); );
} }
} }
Err(err) => {
if let BinstallError::UserAbort = err {
return Err(err);
}
warn!(
"Error while downloading and extracting from fetcher {}: {}",
fetcher.source_name(),
err
);
}
} }
} Ok(false) => (),
Ok(false) => (), Err(err) => {
warn!(
"Error while checking fetcher {}: {}",
fetcher.source_name(),
err
);
}
},
Err(err) => { Err(err) => {
warn!( warn!(
"Error while checking fetcher {}: {}", "Timeout reached while checking fetcher {}: {}",
fetcher.source_name(), fetcher.source_name(),
err err
); );