fix(sync): clear stale server listeners before restart
This commit is contained in:
parent
898947a2b5
commit
5173e3cea7
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -1642,7 +1642,7 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lesavka_client"
|
name = "lesavka_client"
|
||||||
version = "0.14.32"
|
version = "0.14.33"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-stream",
|
"async-stream",
|
||||||
@ -1676,7 +1676,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lesavka_common"
|
name = "lesavka_common"
|
||||||
version = "0.14.32"
|
version = "0.14.33"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64",
|
"base64",
|
||||||
@ -1688,7 +1688,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lesavka_server"
|
name = "lesavka_server"
|
||||||
version = "0.14.32"
|
version = "0.14.33"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64",
|
"base64",
|
||||||
|
|||||||
@ -4,7 +4,7 @@ path = "src/main.rs"
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "lesavka_client"
|
name = "lesavka_client"
|
||||||
version = "0.14.32"
|
version = "0.14.33"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "lesavka_common"
|
name = "lesavka_common"
|
||||||
version = "0.14.32"
|
version = "0.14.33"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
|
|||||||
@ -113,6 +113,114 @@ is_attached_state() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server_bind_addr() {
|
||||||
|
printf '%s\n' "${LESAVKA_SERVER_BIND_ADDR:-0.0.0.0:50051}"
|
||||||
|
}
|
||||||
|
|
||||||
|
server_bind_port() {
|
||||||
|
local bind_addr port
|
||||||
|
bind_addr=$(server_bind_addr)
|
||||||
|
port=${bind_addr##*:}
|
||||||
|
[[ $port =~ ^[0-9]+$ ]] || return 1
|
||||||
|
printf '%s\n' "$port"
|
||||||
|
}
|
||||||
|
|
||||||
|
list_server_listener_pids() {
|
||||||
|
local port
|
||||||
|
port=$(server_bind_port) || return 1
|
||||||
|
sudo lsof -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null | sort -u
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_stale_server_listener() {
|
||||||
|
local port pid cmdline found=0 unexpected=0
|
||||||
|
port=$(server_bind_port) || {
|
||||||
|
echo "⚠️ could not parse LESAVKA_SERVER_BIND_ADDR='$(server_bind_addr)'; skipping stale-listener cleanup."
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
while read -r pid; do
|
||||||
|
[[ -n $pid ]] || continue
|
||||||
|
found=1
|
||||||
|
cmdline=$(sudo ps -o args= -p "$pid" 2>/dev/null || true)
|
||||||
|
if [[ $cmdline == *"/usr/local/bin/lesavka-server"* ]] || [[ $cmdline == *"lesavka-server"* ]]; then
|
||||||
|
echo "⚠️ clearing stale lesavka-server listener on :$port (pid $pid)."
|
||||||
|
sudo kill -TERM "$pid" 2>/dev/null || true
|
||||||
|
else
|
||||||
|
echo "❌ TCP :$port is already owned by an unexpected process (pid $pid): ${cmdline:-<unknown>}." >&2
|
||||||
|
unexpected=1
|
||||||
|
fi
|
||||||
|
done < <(list_server_listener_pids || true)
|
||||||
|
|
||||||
|
if [[ "$unexpected" != "0" ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [[ "$found" == "0" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
for _ in {1..30}; do
|
||||||
|
if ! list_server_listener_pids | grep -q .; then
|
||||||
|
echo "✅ cleared stale lesavka-server listeners on :$port."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
|
||||||
|
while read -r pid; do
|
||||||
|
[[ -n $pid ]] || continue
|
||||||
|
cmdline=$(sudo ps -o args= -p "$pid" 2>/dev/null || true)
|
||||||
|
if [[ $cmdline == *"/usr/local/bin/lesavka-server"* ]] || [[ $cmdline == *"lesavka-server"* ]]; then
|
||||||
|
echo "⚠️ stale lesavka-server listener on :$port survived SIGTERM; sending SIGKILL to pid $pid."
|
||||||
|
sudo kill -KILL "$pid" 2>/dev/null || true
|
||||||
|
else
|
||||||
|
echo "❌ TCP :$port remained busy after cleanup and is owned by an unexpected process (pid $pid): ${cmdline:-<unknown>}." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done < <(list_server_listener_pids || true)
|
||||||
|
|
||||||
|
for _ in {1..30}; do
|
||||||
|
if ! list_server_listener_pids | grep -q .; then
|
||||||
|
echo "✅ cleared stale lesavka-server listeners on :$port."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep 0.1
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "❌ lesavka-server listener on :$port survived cleanup; refusing to start a duplicate server." >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_for_unit_running() {
|
||||||
|
local unit=$1
|
||||||
|
for _ in {1..50}; do
|
||||||
|
if systemctl is-active --quiet "$unit"; then
|
||||||
|
if [[ $(systemctl show "$unit" -p SubState --value 2>/dev/null || true) == "running" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
sleep 0.2
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_server_ready() {
|
||||||
|
local bind_addr
|
||||||
|
bind_addr=$(server_bind_addr)
|
||||||
|
if wait_for_unit_running lesavka-server; then
|
||||||
|
echo "✅ lesavka-server is active and running on ${bind_addr}."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "❌ lesavka-server failed to reach active/running state on ${bind_addr}." >&2
|
||||||
|
sudo systemctl status lesavka-server --no-pager >&2 || true
|
||||||
|
if [[ -s /tmp/lesavka-server.stderr ]]; then
|
||||||
|
echo "---- /tmp/lesavka-server.stderr (tail) ----" >&2
|
||||||
|
sudo tail -n 40 /tmp/lesavka-server.stderr >&2 || true
|
||||||
|
echo "------------------------------------------" >&2
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
normalize_hdmi_connector() {
|
normalize_hdmi_connector() {
|
||||||
local name="$1"
|
local name="$1"
|
||||||
if [[ $name =~ (HDMI-A-[0-9]+)$ ]]; then
|
if [[ $name =~ (HDMI-A-[0-9]+)$ ]]; then
|
||||||
@ -719,7 +827,12 @@ fi
|
|||||||
|
|
||||||
validate_uvc_gadget_ready
|
validate_uvc_gadget_ready
|
||||||
|
|
||||||
|
sudo truncate -s 0 /tmp/lesavka-server.stderr
|
||||||
|
sudo systemctl stop lesavka-server >/dev/null 2>&1 || true
|
||||||
|
clear_stale_server_listener
|
||||||
|
sudo systemctl reset-failed lesavka-server >/dev/null 2>&1 || true
|
||||||
sudo systemctl restart lesavka-server
|
sudo systemctl restart lesavka-server
|
||||||
|
validate_server_ready
|
||||||
INSTALLED_VERSION=$(manifest_package_version "$SRC_DIR/server/Cargo.toml" 2>/dev/null || true)
|
INSTALLED_VERSION=$(manifest_package_version "$SRC_DIR/server/Cargo.toml" 2>/dev/null || true)
|
||||||
INSTALLED_SHA=$(git -C "$SCRIPT_REPO_ROOT" rev-parse --short HEAD 2>/dev/null || true)
|
INSTALLED_SHA=$(git -C "$SCRIPT_REPO_ROOT" rev-parse --short HEAD 2>/dev/null || true)
|
||||||
PERSISTED_CAM_OUTPUT=$(grep '^LESAVKA_CAM_OUTPUT=' /etc/lesavka/server.env 2>/dev/null | tail -n1 | cut -d= -f2- || true)
|
PERSISTED_CAM_OUTPUT=$(grep '^LESAVKA_CAM_OUTPUT=' /etc/lesavka/server.env 2>/dev/null | tail -n1 | cut -d= -f2- || true)
|
||||||
|
|||||||
@ -10,7 +10,7 @@ bench = false
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "lesavka_server"
|
name = "lesavka_server"
|
||||||
version = "0.14.32"
|
version = "0.14.33"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
autobins = false
|
autobins = false
|
||||||
|
|
||||||
|
|||||||
@ -98,6 +98,26 @@ fn server_install_pins_hdmi_camera_and_display_defaults() {
|
|||||||
SERVER_INSTALL.contains("lesavka-uvc already active; runtime settings unchanged."),
|
SERVER_INSTALL.contains("lesavka-uvc already active; runtime settings unchanged."),
|
||||||
"install script should avoid unnecessary UVC restarts when nothing changed"
|
"install script should avoid unnecessary UVC restarts when nothing changed"
|
||||||
);
|
);
|
||||||
|
assert!(
|
||||||
|
SERVER_INSTALL.contains("clear_stale_server_listener"),
|
||||||
|
"install script should clear stale server listeners before restart"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
SERVER_INSTALL.contains("lsof -tiTCP:"),
|
||||||
|
"install script should inspect the bind port before starting a fresh server"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
SERVER_INSTALL.contains("unexpected process"),
|
||||||
|
"install script should fail loud instead of killing an unrelated process on the server port"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
SERVER_INSTALL.contains("validate_server_ready"),
|
||||||
|
"install script should verify that lesavka-server reaches a running state"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
SERVER_INSTALL.contains("failed to reach active/running state"),
|
||||||
|
"install script should explain server startup failures instead of claiming success"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user