131 lines
3.5 KiB
Bash
Executable File
131 lines
3.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
# shellcheck source=scripts/local-debug/env.sh
|
|
source "$ROOT_DIR/scripts/local-debug/env.sh"
|
|
|
|
wait_for_pid_exit() {
|
|
local pid="$1"
|
|
for _ in $(seq 1 20); do
|
|
if ! kill -0 "$pid" 2>/dev/null; then
|
|
return 0
|
|
fi
|
|
sleep 0.25
|
|
done
|
|
return 1
|
|
}
|
|
|
|
descendant_pids() {
|
|
local pid="$1"
|
|
local child
|
|
while IFS= read -r child; do
|
|
[[ -n "$child" ]] || continue
|
|
printf '%s\n' "$child"
|
|
descendant_pids "$child"
|
|
done < <(pgrep -P "$pid" 2>/dev/null || true)
|
|
}
|
|
|
|
stop_pid_tree() {
|
|
local name="$1"
|
|
local root_pid="$2"
|
|
local pids
|
|
local pid
|
|
local forced=0
|
|
|
|
[[ "$root_pid" =~ ^[0-9]+$ ]] || return 0
|
|
pids="$(descendant_pids "$root_pid"; printf '%s\n' "$root_pid")"
|
|
for pid in $pids; do
|
|
kill "$pid" 2>/dev/null || true
|
|
done
|
|
for pid in $pids; do
|
|
if ! wait_for_pid_exit "$pid"; then
|
|
forced=1
|
|
fi
|
|
done
|
|
if [[ "$forced" -eq 1 ]]; then
|
|
printf '%s process tree rooted at pid %s did not stop after SIGTERM; sending SIGKILL\n' "$name" "$root_pid"
|
|
for pid in $pids; do
|
|
kill -9 "$pid" 2>/dev/null || true
|
|
done
|
|
for pid in $pids; do
|
|
wait_for_pid_exit "$pid" || true
|
|
done
|
|
fi
|
|
}
|
|
|
|
stop_matching_processes() {
|
|
local name="$1"
|
|
local pattern="$2"
|
|
local pid
|
|
[[ -n "$pattern" ]] || return 0
|
|
while IFS= read -r pid; do
|
|
[[ "$pid" =~ ^[0-9]+$ ]] || continue
|
|
[[ "$pid" != "$$" ]] || continue
|
|
if kill -0 "$pid" 2>/dev/null; then
|
|
printf 'stopping stale %s pid %s\n' "$name" "$pid"
|
|
stop_pid_tree "$name" "$pid"
|
|
fi
|
|
done < <(pgrep -f "$pattern" 2>/dev/null || true)
|
|
}
|
|
|
|
if [[ ! -d "$LOCAL_DEBUG_PID_DIR" ]]; then
|
|
printf 'no local debug pid directory at %s\n' "$LOCAL_DEBUG_PID_DIR"
|
|
else
|
|
pid_files=("$LOCAL_DEBUG_PID_DIR/platform_web.pid" "$LOCAL_DEBUG_PID_DIR/run.pid" "$LOCAL_DEBUG_PID_DIR/platform.pid")
|
|
for generated_pid_file in "$LOCAL_DEBUG_PID_DIR"/generated-*-run.pid; do
|
|
if [[ -f "$generated_pid_file" ]]; then
|
|
pid_files+=("$generated_pid_file")
|
|
fi
|
|
done
|
|
for pid_file in "${pid_files[@]}"; do
|
|
if [[ ! -f "$pid_file" ]]; then
|
|
continue
|
|
fi
|
|
name="$(basename "$pid_file" .pid)"
|
|
pid="$(<"$pid_file")"
|
|
if kill -0 "$pid" 2>/dev/null; then
|
|
printf 'stopping %s pid %s\n' "$name" "$pid"
|
|
stop_pid_tree "$name" "$pid"
|
|
else
|
|
printf '%s pid %s is not running\n' "$name" "$pid"
|
|
fi
|
|
rm -f "$pid_file"
|
|
done
|
|
fi
|
|
|
|
stop_matching_processes "run bootstrap" "$RUN_BOOTSTRAP_BIN"
|
|
|
|
listener_owned_by_local_debug() {
|
|
local pid="$1"
|
|
local details
|
|
details="$(lsof -nP -p "$pid" 2>/dev/null || true)"
|
|
[[ "$details" == *"$ROOT_DIR"* || "$details" == *"$LOCAL_DEBUG_ROOT"* ]]
|
|
}
|
|
|
|
stop_listener_on_port() {
|
|
local name="$1"
|
|
local port="$2"
|
|
local pid
|
|
pid="$(lsof -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null | head -n 1 || true)"
|
|
if [[ -z "$pid" ]]; then
|
|
return 0
|
|
fi
|
|
|
|
if listener_owned_by_local_debug "$pid"; then
|
|
printf 'stopping %s listener pid %s on port %s\n' "$name" "$pid" "$port"
|
|
kill "$pid" 2>/dev/null || true
|
|
if ! wait_for_pid_exit "$pid"; then
|
|
printf '%s listener pid %s did not stop after SIGTERM; sending SIGKILL\n' "$name" "$pid"
|
|
kill -9 "$pid" 2>/dev/null || true
|
|
wait_for_pid_exit "$pid" || true
|
|
fi
|
|
return 0
|
|
else
|
|
printf '%s port %s is still used by pid %s outside local debug ownership\n' "$name" "$port" "$pid" >&2
|
|
fi
|
|
}
|
|
|
|
stop_listener_on_port platform "$LOCAL_DEBUG_PLATFORM_PORT"
|
|
stop_listener_on_port platform_web "$LOCAL_DEBUG_WEB_PORT"
|