aboutsummaryrefslogtreecommitdiff
path: root/src/session.rs
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-07-05 02:17:45 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-07-05 02:17:45 +0300
commitc78349f422139577f8d7bf5e07f84dcec5a48456 (patch)
tree049cd25431acd355a1ab0923a2e0b6778f766e35 /src/session.rs
parenta4935886afffddf168bec4bbacacf9def6d1776b (diff)
fix: wait for server stop socket cleanup
Diffstat (limited to 'src/session.rs')
-rw-r--r--src/session.rs61
1 files changed, 50 insertions, 11 deletions
diff --git a/src/session.rs b/src/session.rs
index 34d202a5..4dfb2658 100644
--- a/src/session.rs
+++ b/src/session.rs
@@ -233,9 +233,37 @@ pub fn stop_session(name: Option<&str>) -> Result<SessionInfo, String> {
stop_session_with_timeout(name, STOP_WAIT_TIMEOUT)
}
+pub(crate) fn stop_active_server() -> Result<(), String> {
+ let socket_path = active_api_socket_path();
+ let client_socket_path = crate::server::socket_paths::client_socket_path();
+ stop_socket_with_timeout(
+ socket_path.clone(),
+ vec![socket_path, client_socket_path],
+ STOP_WAIT_TIMEOUT,
+ "server",
+ )
+}
+
fn stop_session_with_timeout(name: Option<&str>, timeout: Duration) -> Result<SessionInfo, String> {
- let deadline = Instant::now() + timeout;
let socket_path = api_socket_path_for(name);
+ let client_socket_path = client_socket_path_for(name);
+ let label = format!("session {}", name.unwrap_or(DEFAULT_SESSION_NAME));
+ stop_socket_with_timeout(
+ socket_path.clone(),
+ vec![socket_path, client_socket_path],
+ timeout,
+ &label,
+ )?;
+ Ok(session_info(name))
+}
+
+fn stop_socket_with_timeout(
+ socket_path: PathBuf,
+ stopped_socket_paths: Vec<PathBuf>,
+ timeout: Duration,
+ label: &str,
+) -> Result<(), String> {
+ let deadline = Instant::now() + timeout;
let request = serde_json::json!({
"id": "cli:session:stop",
"method": "server.stop",
@@ -243,8 +271,7 @@ fn stop_session_with_timeout(name: Option<&str>, timeout: Duration) -> Result<Se
});
let stream = crate::ipc::connect_local_stream(&socket_path).map_err(|err| {
format!(
- "session {} is not running or cannot be reached at {}: {err}",
- name.unwrap_or(DEFAULT_SESSION_NAME),
+ "{label} is not running or cannot be reached at {}: {err}",
socket_path.display()
)
})?;
@@ -254,15 +281,19 @@ fn stop_session_with_timeout(name: Option<&str>, timeout: Duration) -> Result<Se
return Err(error.to_string());
}
}
- if !wait_until_stopped_until(&socket_path, deadline) {
+ if !wait_until_stopped_until(&stopped_socket_paths, deadline) {
+ let reachable = reachable_socket_paths(&stopped_socket_paths);
return Err(format!(
- "session {} did not stop within {}ms; socket is still reachable at {}",
- name.unwrap_or(DEFAULT_SESSION_NAME),
+ "{label} did not stop within {}ms; sockets are still reachable at {}",
timeout.as_millis(),
- socket_path.display()
+ reachable
+ .iter()
+ .map(|path| path.display().to_string())
+ .collect::<Vec<_>>()
+ .join(", ")
));
}
- Ok(session_info(name))
+ Ok(())
}
pub fn delete_session(name: &str) -> Result<SessionInfo, String> {
@@ -353,14 +384,22 @@ fn is_running_at(socket_path: &Path) -> bool {
socket_path.exists() && crate::ipc::connect_local_stream(socket_path).is_ok()
}
-fn wait_until_stopped_until(socket_path: &Path, deadline: Instant) -> bool {
+fn wait_until_stopped_until(socket_paths: &[PathBuf], deadline: Instant) -> bool {
while Instant::now() < deadline {
- if !is_running_at(socket_path) {
+ if socket_paths.iter().all(|path| !is_running_at(path)) {
return true;
}
std::thread::sleep(STOP_WAIT_POLL.min(time_until(deadline)));
}
- !is_running_at(socket_path)
+ socket_paths.iter().all(|path| !is_running_at(path))
+}
+
+fn reachable_socket_paths(socket_paths: &[PathBuf]) -> Vec<PathBuf> {
+ socket_paths
+ .iter()
+ .filter(|path| is_running_at(path))
+ .cloned()
+ .collect()
}
fn time_until(deadline: Instant) -> Duration {