#!/usr/bin/env bash # auvops.sh - AUV 容器内运维工具(在容器内直接执行,非宿主机 docker exec) # # 拷贝进容器 /app(backend 根)后运行。后续新增运维能力都收敛到这个文件: # 加一个 cmd_xxx 函数 + 在 main 的 case 里注册一行即可。 # # 用法(容器内): # ./auvops.sh cache-clear # 清空全部缓存(当日数据全新) # ./auvops.sh clean-expired # 只清理已过期的缓存 # ./auvops.sh cache-count # 查看缓存条数 # ./auvops.sh recollect [DATE] # 删除并重采指定交易日(默认当天) # ./auvops.sh sh # 进入交互式 shell # ./auvops.sh help # 查看帮助 # # 依赖: 容器内 python 可用(能 import services.*),工作目录自动切到脚本所在目录。 # # 示例: # ./auvops.sh cache-clear # ./auvops.sh recollect 2026-08-10 # ./auvops.sh cache-count set -euo pipefail # 容器内 backend 根:脚本所在目录(/app) ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "${ROOT}" # 容器内用 python;本机验证时可 PY=./venv/bin/python ./auvops.sh ... PY="${PY:-python}" "${PY}" -c "import services" >/dev/null 2>&1 || { echo "❌ 无法在 ${ROOT} 下 import services(确认已在容器内 /app 且 python 可用)" >&2 exit 1 } # 在容器内跑 python 代码。日期等参数通过环境变量传,避免拼接进代码字符串。 # 用法: py_env "KEY1=val1" "KEY2=val2" <<'EOF' # # EOF py_env() { local env_args=() while [[ "$#" -gt 0 ]]; do env_args+=("${1%%=*}=${1#*=}"); shift done env "${env_args[@]}" "${PY}" - } # ---- 子命令实现 ---- # 清空全部缓存(当日数据全新) cmd_cache_clear() { echo "① 清空全部缓存" "${PY}" - <<'EOF' from services.cache import clear_all clear_all() print(" cache 表已清空") EOF echo "✅ 缓存已清空" } # 只清理已过期缓存 cmd_clean_expired() { echo "① 清理过期缓存" "${PY}" - <<'EOF' from services.cache import clean_expired clean_expired() print(" 过期缓存已清理") EOF echo "✅ 完成" } # 查看缓存条数 cmd_cache_count() { "${PY}" - <<'EOF' from database import get_connection conn = get_connection() try: n = conn.execute("SELECT COUNT(*) FROM cache").fetchone()[0] print(f"缓存条数: {n}") finally: conn.close() EOF } # 删除指定交易日旧数据,并用新选股逻辑重新采集入库 cmd_recollect() { local date="${1:-$(date +%F)}" if ! [[ "${date}" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then echo "❌ 日期格式错误:${date}(应为 YYYY-MM-DD)" >&2 exit 1 fi echo "================================================" echo "🚀 容器: ${HOSTNAME:-unknown} 交易日: ${date}" echo "================================================" echo "① 删除 ${date} 旧数据" py_env "TARGET_DATE=${date}" <<'EOF' import os from database import get_connection date = os.environ["TARGET_DATE"] conn = get_connection() try: for tbl in ("daily_core_stocks", "daily_core_stock_themes", "daily_top_themes"): cur = conn.execute("DELETE FROM " + tbl + " WHERE trade_date = ?", (date,)) print(f" {tbl}: 删除 {cur.rowcount} 行") conn.commit() finally: conn.close() EOF echo "② 用新选股逻辑重采 ${date}" py_env "TARGET_DATE=${date}" <<'EOF' import asyncio import os from services.daily_collector import collect_daily result = asyncio.run(collect_daily(os.environ["TARGET_DATE"])) print(" 结果:", result) EOF echo "✅ 完成" } # 进入交互式 shell cmd_sh() { "${PY}" || true } # 帮助 usage() { awk 'NR >= 2 && /^#/ { sub(/^# ?/, ""); print; next } NR >= 2 && !/^#/ { exit }' "${BASH_SOURCE[0]}" } # ---- 入口 ---- main() { if [[ "$#" -eq 0 ]]; then usage exit 1 fi local cmd="$1"; shift case "${cmd}" in cache-clear|cc) cmd_cache_clear "$@" ;; clean-expired) cmd_clean_expired "$@" ;; cache-count) cmd_cache_count "$@" ;; recollect) cmd_recollect "$@" ;; sh|shell|python) cmd_sh "$@" ;; help|-h|--help) usage ;; *) echo "❌ 未知命令: ${cmd}(./auvops.sh help 查看用法)" >&2; exit 1 ;; esac } main "$@"