feat: update version to 0.5.61 and fix gateway restart loop in tailnet mode
This commit is contained in:
@@ -2,6 +2,11 @@
|
||||
|
||||
All notable changes to the OpenClaw Assistant Home Assistant Add-on will be documented in this file.
|
||||
|
||||
## [0.5.61] - 2026-03-10
|
||||
|
||||
### Fixed
|
||||
- **Gateway restart loop** (issue #95): `openclaw gateway run` spawns `openclaw-gateway` as the actual long-running daemon; the launcher wrapper exits immediately. The old self-restart detection used `pgrep -f "openclaw.*(gateway|node).*run"` which never matched the live daemon name, so the supervisor always fell through to the restart path, found the port occupied, and looped forever with "already listening". Fixed by using the pattern `openclaw.*(gateway|node)` (without `.*run`) which correctly matches `openclaw-gateway`. Additionally, the loopback relay (tailnet mode) is now stopped before restarting the gateway and restarted after, preventing it from holding the port during supervisor-initiated restarts.
|
||||
|
||||
## [0.5.60] - 2026-03-10
|
||||
|
||||
### Fixed
|
||||
@@ -9,8 +14,6 @@ All notable changes to the OpenClaw Assistant Home Assistant Add-on will be docu
|
||||
|
||||
## [0.5.59] - 2026-03-10
|
||||
|
||||
### Fixed
|
||||
- **Gateway restart loop** (issue #95): when the agent or user ran `openclaw gateway restart`, the supervisor loop detected the old PID exiting and immediately spawned a second gateway instance, which collided with the already-restarted one and looped with "another gateway instance is already listening". The supervisor now detects a self-restart (new PID already running on the same port) and re-tracks it instead of spawning a duplicate.
|
||||
- **Remote mode URL not propagated** (issue #93): `start_openclaw_runtime` was reading `gateway.remote.url` back via `openclaw config get`, which can time out (2 s limit at startup) or return an empty/redacted result. The function now uses `$GATEWAY_REMOTE_URL` directly from the already-parsed add-on options, which is the same value the config helper writes to `openclaw.json`.
|
||||
- **Terminal CLI unreachable in tailnet mode** (issue #90): when `gateway_bind_mode=tailnet` (or `access_mode=tailnet_https`), the gateway binds only to the Tailscale IP. The local CLI always connects via `ws://127.0.0.1:PORT`, causing "Gateway not running" inside the add-on terminal. A lightweight loopback relay (Node.js) is now started automatically to forward `127.0.0.1:PORT → TAILSCALE_IP:PORT`, making all terminal CLI commands work normally. Token auth is still enforced end-to-end by the gateway.
|
||||
- **Session lock cleanup ignored non-default agents**: `cleanup_session_locks` was hardcoded to `agents/main/sessions`, skipping stale locks for any agent with a custom `forcedAgentId`. Stale locks could block the gateway from opening sessions for those agents, causing silent fallback to `main`. Cleanup now scans all `agents/*/sessions/` directories.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: OpenClaw Assistant
|
||||
version: "0.5.60"
|
||||
version: "0.5.61"
|
||||
slug: openclaw_assistant
|
||||
description: Run OpenClaw Assistant (OpenClaw-compatible) as a Home Assistant add-on.
|
||||
url: https://github.com/techartdev/OpenClawHomeAssistant
|
||||
|
||||
+43
-22
@@ -492,10 +492,7 @@ shutdown() {
|
||||
wait "${GW_PID}" || true
|
||||
fi
|
||||
|
||||
if [ -n "${GW_RELAY_PID}" ] && kill -0 "${GW_RELAY_PID}" >/dev/null 2>&1; then
|
||||
kill -TERM "${GW_RELAY_PID}" >/dev/null 2>&1 || true
|
||||
wait "${GW_RELAY_PID}" || true
|
||||
fi
|
||||
stop_gw_relay
|
||||
|
||||
if [ "$CLEAN_LOCKS_ON_EXIT" = "true" ]; then
|
||||
cleanup_session_locks || true
|
||||
@@ -811,25 +808,27 @@ PY
|
||||
return 0
|
||||
}
|
||||
|
||||
if ! start_openclaw_runtime; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Loopback relay for tailnet bind mode (issue #90) ---
|
||||
# --- Loopback relay helpers for tailnet bind mode (issue #90) ---
|
||||
# When gateway.bind=tailnet the gateway only listens on the Tailscale IP.
|
||||
# The local CLI always tries ws://127.0.0.1:PORT and fails with
|
||||
# "Gateway not running" even though the gateway is healthy.
|
||||
# A lightweight Node.js relay (loopback-only) forwards those connections
|
||||
# to the Tailscale IP so terminal CLI commands work normally.
|
||||
# Token auth is still enforced end-to-end by the gateway.
|
||||
if [ "$GATEWAY_BIND_MODE" = "tailnet" ]; then
|
||||
TAILSCALE_IP=$(ip -4 addr show tailscale0 2>/dev/null \
|
||||
# These functions start/stop a lightweight Node.js TCP relay on
|
||||
# 127.0.0.1:PORT -> TAILSCALE_IP:PORT so terminal CLI commands work.
|
||||
# IMPORTANT: stop_gw_relay must be called before restarting the gateway;
|
||||
# otherwise the relay holds the loopback port and the new gateway instance
|
||||
# detects it as "already listening" and exits with code 1.
|
||||
start_gw_relay() {
|
||||
if [ "$GATEWAY_BIND_MODE" != "tailnet" ]; then
|
||||
return 0
|
||||
fi
|
||||
local ts_ip
|
||||
ts_ip=$(ip -4 addr show tailscale0 2>/dev/null \
|
||||
| awk '/inet /{gsub(/\/.*/,"",$2); print $2; exit}' || true)
|
||||
if [[ "${TAILSCALE_IP:-}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "INFO: Starting loopback relay for tailnet gateway (127.0.0.1:${GATEWAY_PORT} -> ${TAILSCALE_IP}:${GATEWAY_PORT})"
|
||||
if [[ "${ts_ip:-}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "INFO: Starting loopback relay for tailnet gateway (127.0.0.1:${GATEWAY_PORT} -> ${ts_ip}:${GATEWAY_PORT})"
|
||||
node -e "
|
||||
const net = require('net');
|
||||
const TARGET_HOST = '${TAILSCALE_IP}';
|
||||
const TARGET_HOST = '${ts_ip}';
|
||||
const TARGET_PORT = ${GATEWAY_PORT};
|
||||
const server = net.createServer(function(c) {
|
||||
const t = net.createConnection(TARGET_PORT, TARGET_HOST);
|
||||
@@ -844,7 +843,21 @@ server.listen(TARGET_PORT, '127.0.0.1');" &
|
||||
echo "WARN: tailnet bind mode active but Tailscale IP not found on tailscale0 interface."
|
||||
echo "WARN: Terminal CLI may show gateway as unreachable. Ensure Tailscale is running and restart."
|
||||
fi
|
||||
}
|
||||
|
||||
stop_gw_relay() {
|
||||
if [ -n "${GW_RELAY_PID}" ] && kill -0 "${GW_RELAY_PID}" >/dev/null 2>&1; then
|
||||
kill -TERM "${GW_RELAY_PID}" >/dev/null 2>&1 || true
|
||||
wait "${GW_RELAY_PID}" 2>/dev/null || true
|
||||
GW_RELAY_PID=""
|
||||
fi
|
||||
}
|
||||
|
||||
if ! start_openclaw_runtime; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
start_gw_relay
|
||||
|
||||
# Start web terminal (optional)
|
||||
TTYD_PID_FILE="/var/run/openclaw-ttyd.pid"
|
||||
@@ -967,12 +980,13 @@ while true; do
|
||||
fi
|
||||
|
||||
# Detect agent/user-initiated self-restart (e.g. 'openclaw gateway restart').
|
||||
# When the gateway restarts itself, the old PID exits but a new process immediately
|
||||
# binds the same port. Without this check the supervisor would spawn a second
|
||||
# instance, which fails with "already listening" and loops forever.
|
||||
# Give the new process a moment to start, then re-track it instead of spawning a duplicate.
|
||||
# 'openclaw gateway run' spawns 'openclaw-gateway' as the actual long-running
|
||||
# daemon; the launcher wrapper exits immediately. The old pattern '.*run' never
|
||||
# matched the live daemon name, so the supervisor always fell through to the
|
||||
# restart path, hit the gateway still on the port, and looped forever.
|
||||
# Use the broader pattern that matches both 'openclaw-gateway' and 'openclaw node run'.
|
||||
sleep 1
|
||||
RESTARTED_PID=$(pgrep -f "openclaw.*(gateway|node).*run" 2>/dev/null | head -1 || true)
|
||||
RESTARTED_PID=$(pgrep -f "openclaw.*(gateway|node)" 2>/dev/null | head -1 || true)
|
||||
if [ -n "$RESTARTED_PID" ] && [ "$RESTARTED_PID" != "$GW_PID" ]; then
|
||||
echo "INFO: OpenClaw runtime restarted itself (new PID $RESTARTED_PID); re-tracking."
|
||||
GW_PID="$RESTARTED_PID"
|
||||
@@ -982,8 +996,15 @@ while true; do
|
||||
echo "WARN: OpenClaw runtime exited with code ${GW_EXIT_CODE}. Restarting in 2s..."
|
||||
sleep 2
|
||||
|
||||
# Stop the loopback relay BEFORE restarting the gateway (tailnet mode only).
|
||||
# The relay holds 127.0.0.1:GATEWAY_PORT — leaving it up causes the new gateway
|
||||
# to detect the port as occupied and exit with code 1, re-entering the loop.
|
||||
stop_gw_relay
|
||||
|
||||
if ! start_openclaw_runtime; then
|
||||
echo "ERROR: Failed to restart OpenClaw runtime; retrying in 5s..."
|
||||
sleep 5
|
||||
else
|
||||
start_gw_relay
|
||||
fi
|
||||
done
|
||||
|
||||
Reference in New Issue
Block a user