#!/bin/bash # ============================================================ # config-protector.sh — 配置保护器 # 作用:在每次修改配置前自动备份 # 修改后健康检查失败 → 自动回滚 # 成功 → 标记为新的稳定点 # 由 health-watchdog.sh 联动触发 # 也支持手动调用:config-protector.sh [snapshot|rollback|status] # ============================================================ set -e CONFIG_DIR="$HOME/.hermes" LOG="$HOME/.hermes/watchdog/config-protector.log" mkdir -p "$(dirname "$LOG")" log() { echo "[$(date '+%H:%M:%S')] $*" | tee -a "$LOG"; } # === 快照:记录当前配置状态 === snapshot() { cd "$CONFIG_DIR" # 检查是否有未提交的变更 if git diff --quiet && git diff --cached --quiet; then log "✅ 配置无变更,无需快照" return 0 fi # 有变更 → 自动 commit git add -A 2>/dev/null local changed=$(git diff --cached --name-only | head -5) git commit -m "auto-snapshot $(date '+%Y-%m-%d %H:%M:%S')" 2>&1 | tail -1 | log log "📸 快照已保存(变更文件:${changed:-无描述})" # 标记最近配置 git tag -f last-config 2>/dev/null return 0 } # === 回滚:恢复到上次稳定点 === rollback() { cd "$CONFIG_DIR" local target="${1:-stable}" if ! git rev-parse --verify "$target" 2>/dev/null; then log "❌ 回滚目标 '$target' 不存在" return 1 fi log "⚠️ 开始回滚到 $target..." # 保存当前状态(回滚前的状态,用于诊断) git stash 2>/dev/null || true # 硬重置到目标 git checkout --force "$target" 2>&1 | log log "✅ 已回滚到 $target" log "📋 受影响文件:$(git diff --name-only HEAD~1..HEAD 2>/dev/null | head -10 || echo '首次回滚')" # 创建回滚事件记录 echo "$(date '+%Y-%m-%dT%H:%M:%S')|rollback|$target" >> "$CONFIG_DIR/watchdog/rollback-history.txt" return 0 } # === 标记当前为稳定 === mark_stable() { cd "$CONFIG_DIR" local tag="stable-$(date '+%Y%m%d-%H%M%S')" git tag -f "$tag" 2>/dev/null git tag -f stable 2>/dev/null log "⭐ 已标记 $tag 为稳定点" return 0 } # === 状态:显示配置保护和最近变更 === status() { cd "$CONFIG_DIR" echo "=== 配置保护状态 ===" echo "仓库: $CONFIG_DIR/.git" echo "最近提交:" git log --oneline -5 2>/dev/null || echo " (无提交)" echo "" echo "未跟踪文件:" git status --short 2>/dev/null | head -10 || echo " 全部已跟踪" echo "" echo "稳定标签:" git tag -l 'stable-*' | sort -r | head -5 2>/dev/null || echo " (无)" echo "" if [ -f "$CONFIG_DIR/watchdog/rollback-history.txt" ]; then echo "回滚历史:" tail -3 "$CONFIG_DIR/watchdog/rollback-history.txt" fi } # === 与看门狗联动:健康检测失败时自动回滚 === auto_rollback_if_unhealthy() { # 由 watchdog 调用,检测上次变更后系统是否正常 cd "$CONFIG_DIR" # 检查最近是否有配置变更(30分钟内) local last_change=$(git log --oneline -1 --format="%ct" HEAD 2>/dev/null || echo 0) local now=$(date +%s) local age=$(( (now - last_change) / 60 )) if [ "$age" -gt 30 ]; then # 上次变更超过30分钟,不触发自动回滚 return 0 fi # 检查关键进程 local dead="" for p in zhiyid-new new-api hermes bge_embed_server; do if ! pgrep -f "$p" > /dev/null 2>&1; then dead="$dead $p" fi done if [ -n "$dead" ]; then log "🚨 检测到自动回滚条件:最近配置变更后进程挂了($dead)" log "🔙 自动回滚中..." rollback "stable" log "🔄 回滚完成,重启服务..." # 重启关键服务 systemctl --user restart zhiyid.service bge-embed.service new-api.service 2>/dev/null || true sleep 5 log "✅ 回滚自愈完成" return 0 fi return 0 } # === 主入口 === case "${1:-snapshot}" in snapshot) snapshot ;; rollback) rollback "$2" ;; mark-stable) mark_stable ;; status) status ;; auto-heal) auto_rollback_if_unhealthy ;; *) echo "用法: config-protector.sh [snapshot|rollback |mark-stable|status|auto-heal]" ;; esac