#!/bin/bash set -ex # ========================================== # 1. 环境初始化与核心工具定义 # ========================================== mkdir -p /root/.openclaw/ BACKUP_CMD="python3 /app/sync.py backup" # 定义带锁的备份函数 safe_backup() { echo "[Backup] Attempting to acquire lock..." flock -n /tmp/backup.lock -c "$BACKUP_CMD" || echo "[Backup] Lock busy. Skipped." } # ========================================== # 2. 状态恢复与智能配置映射 (纯决策层) # ========================================== CONFIG_FILE="/root/.openclaw/openclaw.json" MARKER_FILE="/root/.openclaw/.version_marker" # 获取新版本号并拉取云端旧数据 CURRENT_VERSION=$(openclaw --version 2>/dev/null || echo "unknown") # ================= 新增:物理核销本地缓存防线 ================= echo "[Pre-Restore] Clearing local huggingface cache to prevent stale data..." rm -rf /root/.cache/huggingface/hub/* 2>/dev/null || true rm -rf /tmp/*.tar.gz 2>/dev/null || true # ========================================================== python3 /app/sync.py restore || echo "[Restore] No backup found or failed." RESTORED_VERSION=$(cat "$MARKER_FILE" 2>/dev/null || echo "none") # 决策逻辑 if [ ! -s "$CONFIG_FILE" ]; then echo "[Init] No config found. Applying fresh template..." envsubst < /app/openclaw.json > "$CONFIG_FILE" echo "$CURRENT_VERSION" > "$MARKER_FILE" elif [ "$FORCE_OVERWRITE" = "true" ]; then echo "[Config] FORCE_OVERWRITE triggered! Resetting to template..." envsubst < /app/openclaw.json > "$CONFIG_FILE" echo "$CURRENT_VERSION" > "$MARKER_FILE" elif [ "$CURRENT_VERSION" != "$RESTORED_VERSION" ] && [ "$CURRENT_VERSION" != "unknown" ]; then echo "[Upgrade] Upgrading from $RESTORED_VERSION to $CURRENT_VERSION." echo "$CURRENT_VERSION" > "$MARKER_FILE" else echo "[Start] Version matches ($CURRENT_VERSION). Normal boot." fi # ========================================== # 3. 预检、修复与统一固化 (执行层) # ========================================== # 清理浏览器残留缓存 rm -rf /root/.openclaw/browser/*/user-data/Singleton* /tmp/org.chromium.Chromium.* 2>/dev/null || true # 统一交给 doctor 检查和修复 echo "[Doctor] Checking and fixing data structures..." openclaw doctor --fix # 只有在发生版本升级、强制重置或全新安装时,才在开机触发基础备份 if [ "$CURRENT_VERSION" != "$RESTORED_VERSION" ] || [ "$FORCE_OVERWRITE" = "true" ] || [ ! -s "$CONFIG_FILE" ]; then echo "[Init/Upgrade] Performing baseline backup..." safe_backup fi # ========================================== # 4. 主进程启动与优雅关闭 (Graceful Shutdown) # ========================================== echo "[Main] Starting OpenClaw Gateway..." # 真正启动网关的核心命令! openclaw gateway run --port $PORT & MAIN_PID=$! # 关机保护逻辑 shutdown_handler() { echo "[Shutdown] Caught termination signal! Forwarding SIGTERM to OpenClaw (PID $MAIN_PID)..." kill -TERM $MAIN_PID 2>/dev/null || true echo "[Shutdown] Waiting for OpenClaw to safely flush databases..." wait $MAIN_PID || true echo "[Shutdown] OpenClaw exited safely. Performing final monolithic backup..." safe_backup echo "[Shutdown] Data secured. Goodbye." exit 0 } # 捕获系统关机信号 trap shutdown_handler SIGTERM SIGINT # ========================================== # 5. 后台安全巡航备份 & 飞书指令监听器 # ========================================== ( # 记录上一次定时备份的时间戳 LAST_BACKUP_TIME=$(date +%s) BACKUP_INTERVAL=10800 # 3小时 = 10800秒 while kill -0 $MAIN_PID 2>/dev/null; do sleep 5 # 每 5 秒轮询一次,极低性能损耗,但能实现飞书指令的“秒回” CURRENT_TIME=$(date +%s) # 触发条件 1:飞书旁路标记文件被创建 if [ -f "/tmp/trigger_backup" ]; then echo "[巡航守护] Detected manual backup trigger from Feishu!" rm -f "/tmp/trigger_backup" # 消费掉标记 safe_backup LAST_BACKUP_TIME=$CURRENT_TIME # 重置计时器,避免刚手动备份完立马又触发自动备份 fi # 触发条件 2:距离上次备份超过 3 小时 if [ $((CURRENT_TIME - LAST_BACKUP_TIME)) -ge $BACKUP_INTERVAL ]; then echo "[巡航守护] 3 hours passed. Executing scheduled backup..." safe_backup LAST_BACKUP_TIME=$CURRENT_TIME # 重置计时器 fi done ) & LOOP_PID=$! # ========================================== # 6. 主进程阻塞 # ========================================== # 脚本停在这里,维持容器长亮 wait $MAIN_PID # 如果 OpenClaw 异常崩溃(非系统关机),杀掉巡航脚本,做最后一次抢救备份 echo "[Main] Gateway process exited unexpectedly. Attempting final rescue sync..." kill $LOOP_PID 2>/dev/null || true safe_backup