#!/usr/bin/env bash # Run only from the deployed app directory in an administrator SSH session. # It never reads, prints or prompts for secrets; it uses the already-injected # environment of that session/service. set -euo pipefail if [ "${1:-}" != "--confirm-restart" ]; then echo "Usage: ./deploy/restart-school.sh --confirm-restart" >&2 exit 2 fi APP_ROOT="$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)" LOG="${SCHOOL_APP_LOG:-/data0/zqyan/logs/squid_zai_7861.log}" PIDFILE="${SCHOOL_APP_PIDFILE:-${HOME}/.squid_zai_7861.pid}" PORT="${PORT:-7861}" PYTHON_BIN="${MARINE_APP_PYTHON:-/home/zqyan/miniforge3/envs/squid_agent/bin/python3}" if [ ! -x "$PYTHON_BIN" ]; then PYTHON_BIN="$(command -v python3 || true)" fi if [ -z "$PYTHON_BIN" ]; then echo "No usable Python 3 interpreter was found." >&2 exit 1 fi PYTHON_DIR="$(dirname "$PYTHON_BIN")" export PATH="${PYTHON_DIR}:${PATH}" PYTHON_VERSION="$($PYTHON_BIN -c 'import sys; print(f"{sys.version_info[0]}.{sys.version_info[1]}")')" case "$PYTHON_VERSION" in 3.9|3.10|3.11|3.12|3.13) ;; *) echo "Python ${PYTHON_VERSION} is too old; this release requires Python 3.9+." >&2 exit 1 ;; esac # A manual SSH session does not inherit the environment of the already-running # public service. Before touching that service, recover only the fixed runtime # variable allow-list from its own process environment. Values are never # printed, written to disk, or accepted from user input. OLD_PID="$(ps -ef | awk -v port="$PORT" '$0 ~ "uvicorn.*--port " port && $0 !~ /awk/ {print $2; exit}')" if [ -n "$OLD_PID" ] && [ -r "/proc/${OLD_PID}/environ" ]; then eval "$("$PYTHON_BIN" - "$OLD_PID" <<'PY' import os, shlex, sys pid = sys.argv[1] allowed = { "MARINE_API_URL", "MARINE_PROXY_UPSTREAM_URL", "LOCAL_SQUID_DATA_ROOT", "LOCAL_TUNA_DATA_ROOT", "MEMORY_API_URL", "MEMORY_API_TOKEN", "CODEWHALE_RUNTIME_TOKEN", "CODEX_HARNESS_RUNTIME", "REQUIRE_CODEX_HARNESS", "CODEX_PROVIDER", "CODEX_MODEL", "CODEX_DISABLE_WEBSOCKETS", "CODEX_BIN", "CODEX_HOME", "PORT", "PYTHONDONTWRITEBYTECODE", "ZAI_API_KEY", "GLM_API_KEY", "ZHIPU_API_KEY", "HF_TOKEN", "HF_SQUID_DATASET_REPO", "HF_TUNA_DATASET_REPO", "FISHERIES_EXPORT_ROOT", "HF_FISHERIES_CACHE_ROOT", "MARINE_EXPORT_RANGE_MAX_DAYS", "PUBLIC_BASE_URL", "MARINE_PUBLIC_BASE_URL", } with open(f"/proc/{pid}/environ", "rb") as stream: entries = stream.read().split(b"\0") for raw in entries: if b"=" not in raw: continue key, value = raw.split(b"=", 1) name = key.decode("utf-8", "ignore") if name in allowed: print(f"export {name}={shlex.quote(value.decode('utf-8', 'surrogateescape'))}") PY )" fi # Fail before stopping a healthy public service. These values belong to the # existing runtime/service environment; the script never requests or prints # their values. : "${MARINE_API_URL:?Missing runtime configuration: MARINE_API_URL}" if [ -z "${ZAI_API_KEY:-}${GLM_API_KEY:-}${ZHIPU_API_KEY:-}" ]; then echo "Missing model runtime configuration in this shell; old service was not stopped." >&2 exit 1 fi cd "$APP_ROOT" bash -n start.sh PYTHONDONTWRITEBYTECODE=1 "$PYTHON_BIN" scripts/preflight.py if [ -n "$OLD_PID" ]; then kill "$OLD_PID" for _ in 1 2 3 4 5 6 7 8; do kill -0 "$OLD_PID" 2>/dev/null || break sleep 1 done fi nohup env PYTHONDONTWRITEBYTECODE=1 ./start.sh > "$LOG" 2>&1 "$PIDFILE" sleep 8 if ! curl -fsS "http://127.0.0.1:${PORT}/api/status"; then echo >&2 echo "Restart failed. Recent log:" >&2 tail -80 "$LOG" >&2 || true exit 1 fi echo echo "School runtime restarted: pid=${PID}, port=${PORT}, log=${LOG}"