Skip to content

Commit 7ffbaca

Browse files
authored
feat: add simple retry for text file busy (#155)
adds a primitive retry logic for text file busy errors by checking if the file now exists and has the right checksum, in which case we can exit early or retry install
1 parent 357d9e2 commit 7ffbaca

File tree

1 file changed

+54
-2
lines changed

1 file changed

+54
-2
lines changed

crates/svm-rs/src/install.rs

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,12 @@ pub fn blocking_install(version: &Version) -> Result<PathBuf, SvmError> {
5757
// same version of solc.
5858
let _lock = try_lock_file(lock_path)?;
5959

60-
do_install(version, &binbytes, artifact.to_string().as_str())
60+
do_install_and_retry(
61+
version,
62+
&binbytes,
63+
artifact.to_string().as_str(),
64+
&expected_checksum,
65+
)
6166
}
6267

6368
/// Installs the provided version of Solc in the machine.
@@ -98,7 +103,54 @@ pub async fn install(version: &Version) -> Result<PathBuf, SvmError> {
98103
// same version of solc.
99104
let _lock = try_lock_file(lock_path)?;
100105

101-
do_install(version, &binbytes, artifact.to_string().as_str())
106+
do_install_and_retry(
107+
version,
108+
&binbytes,
109+
artifact.to_string().as_str(),
110+
&expected_checksum,
111+
)
112+
}
113+
114+
/// Same as [`do_install`] but retries "text file busy" errors.
115+
fn do_install_and_retry(
116+
version: &Version,
117+
binbytes: &[u8],
118+
artifact: &str,
119+
expected_checksum: &[u8],
120+
) -> Result<PathBuf, SvmError> {
121+
let mut retries = 0;
122+
123+
loop {
124+
return match do_install(version, binbytes, artifact) {
125+
Ok(path) => Ok(path),
126+
Err(err) => {
127+
// installation failed
128+
if retries > 2 {
129+
return Err(err);
130+
}
131+
retries += 1;
132+
// check if this failed due to a text file busy, which indicates that a different process started using the target file
133+
if err.to_string().to_lowercase().contains("text file busy") {
134+
// busy solc can be in use for a while (e.g. if compiling a large project), so we check if the file exists and has the correct checksum
135+
let solc_path = version_binary(&version.to_string());
136+
if solc_path.exists() {
137+
if let Ok(content) = fs::read(&solc_path) {
138+
if ensure_checksum(&content, version, expected_checksum).is_ok() {
139+
// checksum of the existing file matches the expected release checksum
140+
return Ok(solc_path);
141+
}
142+
}
143+
}
144+
145+
// retry after some time
146+
std::thread::sleep(Duration::from_millis(250));
147+
continue;
148+
}
149+
150+
Err(err)
151+
}
152+
};
153+
}
102154
}
103155

104156
fn do_install(version: &Version, binbytes: &[u8], _artifact: &str) -> Result<PathBuf, SvmError> {

0 commit comments

Comments
 (0)