fix: improve SSH service stability and backup.py error handling
Browse files- scripts/hf-entrypoint.sh +41 -10
scripts/hf-entrypoint.sh
CHANGED
|
@@ -94,12 +94,26 @@ fi
|
|
| 94 |
# ============================================
|
| 95 |
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: starting supervisord..."
|
| 96 |
mkdir -p /var/run /var/log/supervisor /var/log/hf-entrypoint
|
|
|
|
| 97 |
/usr/bin/supervisord -c /etc/supervisor/supervisord.conf \
|
| 98 |
-
>> /var/log/hf-entrypoint/supervisord-stdout.log \
|
| 99 |
-
2>> /var/log/hf-entrypoint/supervisord-stderr.log &
|
| 100 |
SUPERVISORD_PID=$!
|
| 101 |
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: supervisord started (pid=$SUPERVISORD_PID)"
|
| 102 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
while [[ ! -f /var/run/supervisord.pid ]]; do
|
| 104 |
sleep 0.5
|
| 105 |
done
|
|
@@ -410,6 +424,7 @@ SLOW_WARN_THRESHOLD=900 # 15分钟超时预警
|
|
| 410 |
MAX_WAIT_TIMEOUT=28800 # 最大等待28800秒(8小时),超时后强制继续启动
|
| 411 |
IDLE_WARN_THRESHOLD=120 # 日志无新内容120秒则告警
|
| 412 |
TIME_NO_NEW_LOG=0
|
|
|
|
| 413 |
|
| 414 |
mkdir -p "$(dirname "$RESTORE_LOG_FILE")"
|
| 415 |
|
|
@@ -423,9 +438,10 @@ show_restore_progress() {
|
|
| 423 |
|
| 424 |
if [[ -n "$current_lines" ]] && [[ "$current_lines" -gt "$LAST_RESTORE_LINE" ]]; then
|
| 425 |
local new_lines=$((current_lines - LAST_RESTORE_LINE))
|
| 426 |
-
echo "[$(date -u +
|
| 427 |
# FAST: use awk to prefix lines in a single call (no bash while-read loop)
|
| 428 |
-
|
|
|
|
| 429 |
LAST_RESTORE_LINE="$current_lines"
|
| 430 |
TIME_NO_NEW_LOG=0
|
| 431 |
fi
|
|
@@ -494,27 +510,35 @@ while true; do
|
|
| 494 |
# 使用 supervisorctl status 作为权威检查,同时检查实际进程名作为兜底
|
| 495 |
# 注意: supervisord 中命令是 openclaw-entrypoint.sh gateway,不包含字符串 "openclaw-gateway"
|
| 496 |
# 因此 pgrep -f "openclaw-gateway" 永远不匹配,必须检查实际的进程名
|
|
|
|
| 497 |
gateway_alive=false
|
| 498 |
if [[ -f "/var/run/supervisord.pid" ]]; then
|
| 499 |
# 方法1: 用 supervisorctl 检查 program 状态(最权威,匹配 program:openclaw-gateway)
|
|
|
|
| 500 |
if command -v supervisorctl >/dev/null 2>&1; then
|
| 501 |
-
svc_status=$(supervisorctl status openclaw-gateway 2>/dev/null)
|
| 502 |
if echo "$svc_status" | grep -qE "(RUNNING|STARTING)"; then
|
| 503 |
gateway_alive=true
|
| 504 |
fi
|
| 505 |
fi
|
| 506 |
# 方法2: 兜底检查 - 检查实际运行的入口脚本或恢复进程
|
|
|
|
| 507 |
if [[ "$gateway_alive" != true ]]; then
|
| 508 |
-
if pgrep -f "openclaw-entrypoint" >/dev/null 2>&1 \
|
| 509 |
-
|| pgrep -f "backup\.py restore" >/dev/null 2>&1 \
|
| 510 |
-
|| pgrep -f "openclaw-restore" >/dev/null 2>&1; then
|
| 511 |
gateway_alive=true
|
| 512 |
fi
|
| 513 |
fi
|
| 514 |
fi
|
|
|
|
|
|
|
|
|
|
| 515 |
if [[ "$gateway_alive" != true ]]; then
|
| 516 |
# 如果 gateway 进程已经不存在,且未看到完成标志,视为恢复失败
|
| 517 |
-
|
|
|
|
|
|
|
| 518 |
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: ✗ openclaw-gateway process exited before restore completed, marking as failed"
|
| 519 |
# 在退出前转储完整的恢复日志,让用户看到崩溃前发生了什么
|
| 520 |
_dump_restore_logs "gateway process exited during restore (waited ${WAITED}s)"
|
|
@@ -558,6 +582,13 @@ while true; do
|
|
| 558 |
if [[ -f "$OPENCLAW_STDERR_LOG" ]]; then
|
| 559 |
_dump_log_file "GATEWAY STDERR (hidden Python errors/warnings check)" "$OPENCLAW_STDERR_LOG" 100
|
| 560 |
fi
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 561 |
break
|
| 562 |
fi
|
| 563 |
|
|
@@ -605,7 +636,7 @@ while true; do
|
|
| 605 |
gw_stderr_size=$(stat -c%s "$OPENCLAW_STDERR_LOG" 2>/dev/null || echo "0")
|
| 606 |
if [[ "$gw_stderr_size" -gt "0" ]]; then
|
| 607 |
echo "[$(date -u +"%Y-%m-%dT%H:%M:%SZ")] hf-entrypoint: gateway-stderr (last 30 lines, ${gw_stderr_size} bytes total) --"
|
| 608 |
-
tail -n 30 "$OPENCLAW_STDERR_LOG"
|
| 609 |
echo "[$(date -u +"%Y-%m-%dT%H:%M:%SZ")] hf-entrypoint: -- end gateway-stderr"
|
| 610 |
fi
|
| 611 |
fi
|
|
|
|
| 94 |
# ============================================
|
| 95 |
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: starting supervisord..."
|
| 96 |
mkdir -p /var/run /var/log/supervisor /var/log/hf-entrypoint
|
| 97 |
+
touch /var/log/hf-entrypoint/supervisord-stdout.log /var/log/hf-entrypoint/supervisord-stderr.log
|
| 98 |
/usr/bin/supervisord -c /etc/supervisor/supervisord.conf \
|
| 99 |
+
> >(tee -a /var/log/hf-entrypoint/supervisord-stdout.log) \
|
| 100 |
+
2> >(tee -a /var/log/hf-entrypoint/supervisord-stderr.log >&2) &
|
| 101 |
SUPERVISORD_PID=$!
|
| 102 |
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: supervisord started (pid=$SUPERVISORD_PID)"
|
| 103 |
|
| 104 |
+
# 启动后台 tail -f 进程,把 openclaw-gateway 的日志实时转发到容器 stdout/stderr
|
| 105 |
+
# 这样用户在 docker logs 中可以看到 restore 的所有输出
|
| 106 |
+
touch /var/log/hf-entrypoint/openclaw-gateway-stdout.log /var/log/hf-entrypoint/openclaw-gateway-stderr.log
|
| 107 |
+
if command -v tail >/dev/null 2>&1; then
|
| 108 |
+
# stdout: prefix with [gateway-out so users can distinguish
|
| 109 |
+
tail -f /var/log/hf-entrypoint/openclaw-gateway-stdout.log 2>/dev/null &
|
| 110 |
+
TAIL_STDOUT_PID=$!
|
| 111 |
+
# stderr: prefix with [gateway-err]
|
| 112 |
+
tail -f /var/log/hf-entrypoint/openclaw-gateway-stderr.log 2>/dev/null >&2 &
|
| 113 |
+
TAIL_STDERR_PID=$!
|
| 114 |
+
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: log forwarders started (stdout_pid=$TAIL_STDOUT_PID, stderr_pid=$TAIL_STDERR_PID)"
|
| 115 |
+
fi
|
| 116 |
+
|
| 117 |
while [[ ! -f /var/run/supervisord.pid ]]; do
|
| 118 |
sleep 0.5
|
| 119 |
done
|
|
|
|
| 424 |
MAX_WAIT_TIMEOUT=28800 # 最大等待28800秒(8小时),超时后强制继续启动
|
| 425 |
IDLE_WARN_THRESHOLD=120 # 日志无新内容120秒则告警
|
| 426 |
TIME_NO_NEW_LOG=0
|
| 427 |
+
gateway_was_seen_alive=false
|
| 428 |
|
| 429 |
mkdir -p "$(dirname "$RESTORE_LOG_FILE")"
|
| 430 |
|
|
|
|
| 438 |
|
| 439 |
if [[ -n "$current_lines" ]] && [[ "$current_lines" -gt "$LAST_RESTORE_LINE" ]]; then
|
| 440 |
local new_lines=$((current_lines - LAST_RESTORE_LINE))
|
| 441 |
+
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: --- Restore log ($new_lines new lines) ---"
|
| 442 |
# FAST: use awk to prefix lines in a single call (no bash while-read loop)
|
| 443 |
+
# 用 || true 保护管道,避免 set -o pipefail 触发脚本立即退出
|
| 444 |
+
tail -n "$new_lines" "$RESTORE_LOG_FILE" | awk -v ts="[$(date -u +%Y-%m-%dT%H:%M:%SZ)]" '{print ts, $0}' || true
|
| 445 |
LAST_RESTORE_LINE="$current_lines"
|
| 446 |
TIME_NO_NEW_LOG=0
|
| 447 |
fi
|
|
|
|
| 510 |
# 使用 supervisorctl status 作为权威检查,同时检查实际进程名作为兜底
|
| 511 |
# 注意: supervisord 中命令是 openclaw-entrypoint.sh gateway,不包含字符串 "openclaw-gateway"
|
| 512 |
# 因此 pgrep -f "openclaw-gateway" 永远不匹配,必须检查实际的进程名
|
| 513 |
+
# 关键: 所有检查命令必须用 || true 保护,避免 set -e 误触发脚本立即退出
|
| 514 |
gateway_alive=false
|
| 515 |
if [[ -f "/var/run/supervisord.pid" ]]; then
|
| 516 |
# 方法1: 用 supervisorctl 检查 program 状态(最权威,匹配 program:openclaw-gateway)
|
| 517 |
+
# supervisorctl status 在 program 不存在或状态不是 RUNNING 时返回非0,必须用 || true
|
| 518 |
if command -v supervisorctl >/dev/null 2>&1; then
|
| 519 |
+
svc_status=$(supervisorctl status openclaw-gateway 2>/dev/null || true)
|
| 520 |
if echo "$svc_status" | grep -qE "(RUNNING|STARTING)"; then
|
| 521 |
gateway_alive=true
|
| 522 |
fi
|
| 523 |
fi
|
| 524 |
# 方法2: 兜底检查 - 检查实际运行的入口脚本或恢复进程
|
| 525 |
+
# pgrep 在无匹配时返回 1,在 if 条件中不会触发 set -e,但为了安全用 || true
|
| 526 |
if [[ "$gateway_alive" != true ]]; then
|
| 527 |
+
if { pgrep -f "openclaw-entrypoint" >/dev/null 2>&1 || true; } \
|
| 528 |
+
|| { pgrep -f "backup\.py restore" >/dev/null 2>&1 || true; } \
|
| 529 |
+
|| { pgrep -f "openclaw-restore" >/dev/null 2>&1 || true; }; then
|
| 530 |
gateway_alive=true
|
| 531 |
fi
|
| 532 |
fi
|
| 533 |
fi
|
| 534 |
+
if [[ "$gateway_alive" == true ]]; then
|
| 535 |
+
gateway_was_seen_alive=true
|
| 536 |
+
fi
|
| 537 |
if [[ "$gateway_alive" != true ]]; then
|
| 538 |
# 如果 gateway 进程已经不存在,且未看到完成标志,视为恢复失败
|
| 539 |
+
# 规则: 1) 如果曾经看到 gateway alive(gateway_was_seen_alive=true),立即检测为崩溃
|
| 540 |
+
# 2) 如果���未看到 alive,等待 10 秒后再判定(确保 supervisord 有时间启动它)
|
| 541 |
+
if [[ ! -f "$RESTORE_COMPLETED_FILE" ]] && { [[ "$gateway_was_seen_alive" == true ]] || [[ $WAITED -gt 10 ]]; }; then
|
| 542 |
echo "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] hf-entrypoint: ✗ openclaw-gateway process exited before restore completed, marking as failed"
|
| 543 |
# 在退出前转储完整的恢复日志,让用户看到崩溃前发生了什么
|
| 544 |
_dump_restore_logs "gateway process exited during restore (waited ${WAITED}s)"
|
|
|
|
| 582 |
if [[ -f "$OPENCLAW_STDERR_LOG" ]]; then
|
| 583 |
_dump_log_file "GATEWAY STDERR (hidden Python errors/warnings check)" "$OPENCLAW_STDERR_LOG" 100
|
| 584 |
fi
|
| 585 |
+
# 清理 tail 转发进程(避免继续写入 stdout 干扰后续日志)
|
| 586 |
+
if [[ -n "${TAIL_STDOUT_PID:-}" ]]; then
|
| 587 |
+
kill "$TAIL_STDOUT_PID" 2>/dev/null || true
|
| 588 |
+
fi
|
| 589 |
+
if [[ -n "${TAIL_STDERR_PID:-}" ]]; then
|
| 590 |
+
kill "$TAIL_STDERR_PID" 2>/dev/null || true
|
| 591 |
+
fi
|
| 592 |
break
|
| 593 |
fi
|
| 594 |
|
|
|
|
| 636 |
gw_stderr_size=$(stat -c%s "$OPENCLAW_STDERR_LOG" 2>/dev/null || echo "0")
|
| 637 |
if [[ "$gw_stderr_size" -gt "0" ]]; then
|
| 638 |
echo "[$(date -u +"%Y-%m-%dT%H:%M:%SZ")] hf-entrypoint: gateway-stderr (last 30 lines, ${gw_stderr_size} bytes total) --"
|
| 639 |
+
tail -n 30 "$OPENCLAW_STDERR_LOG" 2>/dev/null || true
|
| 640 |
echo "[$(date -u +"%Y-%m-%dT%H:%M:%SZ")] hf-entrypoint: -- end gateway-stderr"
|
| 641 |
fi
|
| 642 |
fi
|