Skip to content

Commit f41ebad

Browse files
authored
fix docker lock hanging forever (#133)
1 parent 1cfc561 commit f41ebad

File tree

1 file changed

+21
-3
lines changed

1 file changed

+21
-3
lines changed

src/clementine/nodes.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,12 @@ pub async fn ensure_docker_client_if_needed() -> std::result::Result<Option<Path
463463
.filter(|u| !u.is_empty())
464464
.unwrap_or_else(|| DEFAULT_DOCKER_CLIENT_URL.to_string());
465465

466+
// If the docker client already exists, short-circuit without taking the lock
467+
let target_path = get_workspace_root().join("resources/docker/docker-linux-amd64");
468+
if target_path.exists() {
469+
return Ok(Some(target_path));
470+
}
471+
466472
// Prepare lock file next to the docker binary directory
467473
let lock_file_path = get_workspace_root().join("resources/docker/.docker.lock");
468474
if let Some(dir) = lock_file_path.parent() {
@@ -475,9 +481,21 @@ pub async fn ensure_docker_client_if_needed() -> std::result::Result<Option<Path
475481
.truncate(false)
476482
.open(&lock_file_path)?;
477483

478-
// Acquire an exclusive cross-process lock
479-
use fs2::FileExt;
480-
lock_file.lock_exclusive()?;
484+
// Acquire an exclusive cross-process lock with timeout to avoid deadlocks
485+
let start = Instant::now();
486+
let timeout = Duration::from_secs(30);
487+
loop {
488+
// Prefer a non-blocking try-lock; retry until timeout
489+
if fs2::FileExt::try_lock_exclusive(&lock_file).is_ok() {
490+
break;
491+
}
492+
if start.elapsed() >= timeout {
493+
return Err(std::io::Error::other(
494+
"Failed to acquire docker client lock within timeout",
495+
));
496+
}
497+
std::thread::sleep(std::time::Duration::from_millis(50));
498+
}
481499

482500
// Ensure we always release the lock
483501
let res = async {

0 commit comments

Comments
 (0)