* Release PQ (v0.51.456): start.sh detects an already-running server (#4308) start.sh now probes /health (best-effort, 2s, curl/wget) before launching bootstrap.py; if a server already answers it prints a clear 'already running + how to restart' message and exits 0 instead of spawning a child that fails to bind. Brings the detached start.sh path to parity with ctl.sh's double-start refusal. Container path (server.py direct) unaffected. Co-authored-by: tomas-forgac * gate fix (Codex CORE): parse $@ for --host/--host=/positional port in the start.sh preflight bootstrap.py accepts a positional port + --host that override the env defaults; the preflight probed env/defaults only, so './start.sh <altport>' while a server ran on the env-default port falsely reported 'already running' and refused the legitimate launch. Now scans $@ the same way bootstrap.py's argparse does before building the /health probe URL. --------- Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
This commit is contained in:
1 parent
50e7589a92
commit
44032ab5ab
2 files changed
+97
No files matched your search
@@ -7,6 +7,12 @@
|
||||
|
||||
- **Windows pytest-harness compatibility (#3664).** Hardened the test suite to run on Windows: profile-home fallback paths are path-normalized, strict POSIX file-mode (`0o600`) assertions are gated behind `os.name != "nt"` (Linux still asserts them at full strictness), the conftest cleanup handles Windows process-tree/port teardown and the Py3.12+ `shutil.rmtree` `onexc` shim, and tests that require `fork`/`fcntl` carry `@requires_fork` / `@requires_fcntl` markers (which never skip on Linux). Test-only — no runtime or app behavior change, no Linux CI behavior change. (#4254, #4255, #4256, #4257, #4259, #4263, #4266, #4274)
|
||||
|
||||
## [v0.51.456] — 2026-06-16 — Release PQ (start.sh tells you when the server is already running)
|
||||
|
||||
### Changed
|
||||
|
||||
- **`./start.sh` now detects an already-running server instead of pretending to start a new one.** Previously, running `./start.sh` while a server was already bound to the host:port would have `bootstrap.py` spawn a child that fails to bind and dies, while the existing instance answered the `/health` probe — so the script reported "ready" and exited 0 without actually starting anything. `start.sh` now probes `/health` first (best-effort, 2s timeout, via `curl`/`wget`; skipped if neither is present) and, when a server already answers, prints a clear message that nothing was (re)started plus how to restart (`./ctl.sh restart`, or stop-the-PID + `./start.sh`), then exits 0. This brings the detached `start.sh` path to parity with `ctl.sh`'s existing double-start refusal. The container path (which runs `server.py` directly) is unaffected. (#4308)
|
||||
|
||||
## [v0.51.455] — 2026-06-16 — Release PP (drop stale background-process completions instead of prepending them to a later turn)
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -62,4 +62,95 @@ if [[ -z "${PYTHON}" ]]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# Pre-flight: detect an already-running server before launching bootstrap.py.
|
||||
#
|
||||
# bootstrap.py's detached (non-foreground) path spawns server.py, then probes
|
||||
# /health and reports success once *anything* answers. If a server is already
|
||||
# bound to this host:port, the freshly spawned child fails to bind and dies,
|
||||
# but the EXISTING (often orphaned) server answers the /health probe — so
|
||||
# bootstrap.py prints "ready" and exits 0 without having started anything. The
|
||||
# user just keeps re-confirming the old instance on every run.
|
||||
#
|
||||
# To avoid that, probe /health here first. If a server is already up, tell the
|
||||
# user plainly that nothing was (re)started and how to restart, then exit 0.
|
||||
# ctl.sh already refuses to double-start via PID/state tracking; this brings
|
||||
# the detached start.sh path to parity using a health probe (start.sh keeps no
|
||||
# PID file of its own).
|
||||
#
|
||||
# Resolve host/port the same way bootstrap.py does: HERMES_WEBUI_HOST /
|
||||
# HERMES_WEBUI_PORT (possibly just sourced from .env above), else the
|
||||
# bootstrap.py defaults of 127.0.0.1 / 8787. A 0.0.0.0 / :: bind is probed via
|
||||
# loopback, matching server.py's _abort_if_already_serving.
|
||||
_hermes_host="${HERMES_WEBUI_HOST:-127.0.0.1}"
|
||||
_hermes_port="${HERMES_WEBUI_PORT:-8787}"
|
||||
|
||||
# CLI args override the env/defaults exactly as bootstrap.py's argparse does
|
||||
# (`port` is the first bare numeric positional; `--host VALUE` / `--host=VALUE`).
|
||||
# Without this, `./start.sh <port>` or `--host X` would probe the wrong endpoint
|
||||
# and could falsely report "already running" against a different instance.
|
||||
_hermes_args=("$@")
|
||||
_hermes_i=0
|
||||
while [[ ${_hermes_i} -lt ${#_hermes_args[@]} ]]; do
|
||||
_hermes_arg="${_hermes_args[${_hermes_i}]}"
|
||||
case "${_hermes_arg}" in
|
||||
--host)
|
||||
_hermes_next=$(( _hermes_i + 1 ))
|
||||
if [[ ${_hermes_next} -lt ${#_hermes_args[@]} ]]; then
|
||||
_hermes_host="${_hermes_args[${_hermes_next}]}"
|
||||
_hermes_i=${_hermes_next}
|
||||
fi
|
||||
;;
|
||||
--host=*)
|
||||
_hermes_host="${_hermes_arg#--host=}"
|
||||
;;
|
||||
--*)
|
||||
: # other flags (e.g. --no-browser) carry no positional value here
|
||||
;;
|
||||
*)
|
||||
# First bare numeric positional is the port (bootstrap.py: nargs="?").
|
||||
if [[ "${_hermes_arg}" =~ ^[0-9]+$ ]]; then
|
||||
_hermes_port="${_hermes_arg}"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
_hermes_i=$(( _hermes_i + 1 ))
|
||||
done
|
||||
|
||||
case "${_hermes_host}" in
|
||||
0.0.0.0|""|::|"[::]") _hermes_probe_host="127.0.0.1" ;;
|
||||
*) _hermes_probe_host="${_hermes_host}" ;;
|
||||
esac
|
||||
_hermes_health_url="http://${_hermes_probe_host}:${_hermes_port}/health"
|
||||
|
||||
# Best-effort probe. If neither curl nor wget is present we skip the check and
|
||||
# fall through to the normal launch (unchanged behavior). Short 2s timeout so a
|
||||
# normal cold start is not delayed.
|
||||
_hermes_already_up=""
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
_hermes_already_up="$(curl -fsS --max-time 2 "${_hermes_health_url}" 2>/dev/null || true)"
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
_hermes_already_up="$(wget -qO- --timeout=2 --tries=1 "${_hermes_health_url}" 2>/dev/null || true)"
|
||||
fi
|
||||
|
||||
if [[ -n "${_hermes_already_up}" ]]; then
|
||||
cat >&2 <<EOF
|
||||
[==] Hermes WebUI is already running at http://${_hermes_probe_host}:${_hermes_port}
|
||||
The server was NOT started again (start.sh does not double-start).
|
||||
|
||||
If you need to restart the server, do the following:
|
||||
|
||||
Preferred — use the daemon controller:
|
||||
./ctl.sh restart
|
||||
|
||||
Otherwise, stop the running server and start it again manually:
|
||||
1. Find the process listening on port ${_hermes_port}:
|
||||
lsof -iTCP:${_hermes_port} -sTCP:LISTEN # macOS / Linux
|
||||
2. Stop it (use -9 only if it ignores a normal stop):
|
||||
kill <PID>
|
||||
3. Start it again:
|
||||
./start.sh
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
exec "${PYTHON}" "${REPO_ROOT}/bootstrap.py" --no-browser "$@"
|
||||
Reference in new issue
Block a user