[全量] 初始化项目代码、配置、文档及Agent协同harness
This commit is contained in:
135
scripts/backend-pack.sh
Executable file
135
scripts/backend-pack.sh
Executable file
@@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env bash
|
||||
# 须用 bash 执行
|
||||
[ -n "${BASH_VERSION:-}" ] || exec /usr/bin/env bash "$0" ${1+"$@"}
|
||||
# 在 chat_web_backend 执行 mvn package,将产物复制为 backend/chat_web_yj.jar(与 backend-restart.sh 一致)
|
||||
# 日志:gangyan/logs/backend-pack.log
|
||||
set -euo pipefail
|
||||
source "$(cd "$(dirname "$0")" && pwd)/common-restart.sh"
|
||||
LOG_FILE="$LOG_DIR/backend-pack.log"
|
||||
if ! ( umask 022; : >>"$LOG_FILE" ) 2>/dev/null; then
|
||||
mkdir -p "${HOME}/.gangyan/logs"
|
||||
LOG_FILE="${HOME}/.gangyan/logs/backend-pack.log"
|
||||
fi
|
||||
|
||||
export JAVA_HOME="${JAVA_HOME:-/usr/lib/jvm/java-11-openjdk-amd64}"
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
|
||||
BACKEND_SRC="$GANGYAN_ROOT/chat_web_backend"
|
||||
JAR_BUILD="$BACKEND_SRC/target/chat_web_backend.jar"
|
||||
JAR_RUN="$GANGYAN_ROOT/backend/chat_web_yj.jar"
|
||||
|
||||
log_tee() {
|
||||
log_line "$@" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
log_tee "======== 编译打包 Java 后端 ========"
|
||||
log_tee "JAVA_HOME=$JAVA_HOME"
|
||||
|
||||
if ! command -v mvn >/dev/null 2>&1; then
|
||||
log_tee "错误: 未找到 mvn,请先安装 Maven 并加入 PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$BACKEND_SRC/pom.xml" ]; then
|
||||
log_tee "错误: 未找到 $BACKEND_SRC/pom.xml"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$GANGYAN_ROOT/backend"
|
||||
cd "$BACKEND_SRC"
|
||||
|
||||
# 目标目录若被 root 生成,会导致普通用户无法写入(常见表现:Error while storing the mojo status)。
|
||||
# 这里提前检测并给出可执行修复命令。
|
||||
if [ -d "$BACKEND_SRC/target" ] && [ ! -w "$BACKEND_SRC/target" ]; then
|
||||
log_tee "错误: $BACKEND_SRC/target 不可写(可能之前用 root 打过包)。"
|
||||
log_tee "请执行其一后重试:"
|
||||
log_tee " 1) sudo chown -R $(id -un):$(id -gn) \"$BACKEND_SRC/target\""
|
||||
log_tee " 2) sudo rm -rf \"$BACKEND_SRC/target\""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Maven 自身 JVM:内存过小会频繁 GC;可用 export MAVEN_OPTS='...' 覆盖
|
||||
export MAVEN_OPTS="${MAVEN_OPTS:--Xmx1536m -XX:+TieredCompilation -XX:TieredStopAtLevel=1}"
|
||||
|
||||
# 依赖已缓存在 ~/.m2 时: export MAVEN_OFFLINE=1(不访问远程仓库,失败则去掉再跑)
|
||||
MVN_OFFLINE=()
|
||||
if [ "${MAVEN_OFFLINE:-}" = "1" ]; then
|
||||
MVN_OFFLINE=(-o)
|
||||
log_tee "MAVEN_OFFLINE=1:使用 mvn -o(缓存不全会失败,去掉环境变量再跑一次)"
|
||||
fi
|
||||
|
||||
# -------- 远程仓库预检:中央仓库/镜像太慢或不可达则直接退出,避免 mvn 长时间卡在 Downloading --------
|
||||
# 跳过预检: export SKIP_MAVEN_NETCHECK=1
|
||||
# 测速地址(默认与 pom 首选源一致:华为云): export MAVEN_NETCHECK_URL='https://mirrors.tencent.com/nexus/...'
|
||||
# 总耗时超过即视为过慢(秒): export MAVEN_NETCHECK_MAX_SEC=15
|
||||
if [ "${MAVEN_OFFLINE:-}" != "1" ] && [ "${SKIP_MAVEN_NETCHECK:-}" != "1" ]; then
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
NET_URL="${MAVEN_NETCHECK_URL:-https://repo.huaweicloud.com/repository/maven/org/apache/maven/apache-maven/maven-metadata.xml}"
|
||||
# 判定「过慢」的耗时上限(秒);curl 单次请求上限单独设大些,便于测出真实耗时
|
||||
MAX_SEC="${MAVEN_NETCHECK_MAX_SEC:-15}"
|
||||
CURL_MAX="${MAVEN_NETCHECK_CURL_MAX_SEC:-60}"
|
||||
log_tee "Maven 仓库预检(样本下载总耗时 > ${MAX_SEC}s 则中止;curl 上限 ${CURL_MAX}s): $NET_URL"
|
||||
# shellcheck disable=SC2086
|
||||
OUT=$(curl -sS -o /dev/null -w '%{http_code} %{time_total} %{speed_download} %{size_download}' \
|
||||
--connect-timeout 10 --max-time "$CURL_MAX" "$NET_URL" 2>/dev/null) || OUT="000 999 0 0"
|
||||
read -r CODE T_SEC SPD SZ <<< "$OUT"
|
||||
CODE=${CODE:-000}
|
||||
T_SEC=${T_SEC:-999}
|
||||
SPD=${SPD:-0}
|
||||
SZ=${SZ:-0}
|
||||
if [ "$CODE" != "200" ]; then
|
||||
log_tee "预检失败:HTTP $CODE,无法稳定访问该仓库。"
|
||||
log_tee "可选:① 配置 ~/.m2/settings.xml 镜像后设 MAVEN_NETCHECK_URL 指向镜像测速;② 依赖已在 ~/.m2 时 export MAVEN_OFFLINE=1 再打包;③ 仍要尝试 export SKIP_MAVEN_NETCHECK=1"
|
||||
exit 1
|
||||
fi
|
||||
# 小文件平均速度易受握手影响,以「总耗时」为主;大文件再参考速度
|
||||
if awk -v t="$T_SEC" -v m="$MAX_SEC" 'BEGIN { exit !(t + 0 > m + 0) }'; then
|
||||
log_tee "预检失败:下载耗时 ${T_SEC}s,超过 ${MAX_SEC}s(当前渠道过慢)。"
|
||||
log_tee "可选:① 换网络或配置国内镜像;② export MAVEN_OFFLINE=1(仅用本地缓存);③ export SKIP_MAVEN_NETCHECK=1 强制继续"
|
||||
exit 1
|
||||
fi
|
||||
if awk -v sz="$SZ" -v spd="$SPD" 'BEGIN { exit !((sz + 0 > 8000) && (spd + 0 < 15000)) }'; then
|
||||
log_tee "预检失败:约 ${SZ}B 的样本下载平均仅 ${SPD} B/s,持续过慢。"
|
||||
log_tee "可选:配置镜像、MAVEN_OFFLINE=1 或 SKIP_MAVEN_NETCHECK=1(同上)"
|
||||
exit 1
|
||||
fi
|
||||
log_tee "预检通过:HTTP $CODE,耗时 ${T_SEC}s,样本 ${SZ}B。"
|
||||
else
|
||||
log_tee "未找到 curl,跳过仓库预检(建议安装 curl,或设置 SKIP_MAVEN_NETCHECK=1)"
|
||||
fi
|
||||
elif [ "${MAVEN_OFFLINE:-}" = "1" ]; then
|
||||
log_tee "已 MAVEN_OFFLINE=1,跳过仓库网速预检。"
|
||||
elif [ "${SKIP_MAVEN_NETCHECK:-}" = "1" ]; then
|
||||
log_tee "已 SKIP_MAVEN_NETCHECK=1,跳过仓库网速预检。"
|
||||
fi
|
||||
|
||||
# 默认跳过测试源码编译与执行(比仅 -DskipTests 更快)。要编译测试: export MAVEN_SKIP_TEST_COMPILE=0
|
||||
if [ "${MAVEN_SKIP_TEST_COMPILE:-1}" = "1" ]; then
|
||||
TEST_SKIP=(-Dmaven.test.skip=true)
|
||||
log_tee "MAVEN_SKIP_TEST_COMPILE=1:使用 -Dmaven.test.skip=true(不编译 test 源码)"
|
||||
else
|
||||
TEST_SKIP=(-DskipTests)
|
||||
log_tee "MAVEN_SKIP_TEST_COMPILE=0:仅 -DskipTests(仍编译 test 源码)"
|
||||
fi
|
||||
|
||||
# -T 1C:多核并行构建;单模块也有少量收益
|
||||
# 无 javadoc/source 插件时跳过属性无害
|
||||
# 依赖解析缓存“找不到”时可强制刷新:export MAVEN_FORCE_UPDATE=1(等价 mvn -U)
|
||||
MVN_UPDATE=()
|
||||
if [ "${MAVEN_FORCE_UPDATE:-0}" = "1" ]; then
|
||||
MVN_UPDATE=(-U)
|
||||
log_tee "MAVEN_FORCE_UPDATE=1:使用 mvn -U(强制刷新依赖解析缓存)"
|
||||
fi
|
||||
log_tee "执行: mvn ${MVN_OFFLINE[*]} ${MVN_UPDATE[*]} -T 1C ${TEST_SKIP[*]} -Dmaven.javadoc.skip=true -Dmaven.source.skip=true package"
|
||||
set -o pipefail
|
||||
mvn "${MVN_OFFLINE[@]}" "${MVN_UPDATE[@]}" -T 1C "${TEST_SKIP[@]}" -Dmaven.javadoc.skip=true -Dmaven.source.skip=true package 2>&1 | tee -a "$LOG_FILE"
|
||||
|
||||
if [ ! -f "$JAR_BUILD" ]; then
|
||||
log_tee "错误: 未生成 $JAR_BUILD"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cp -f "$JAR_BUILD" "$JAR_RUN"
|
||||
log_tee "已复制: $JAR_BUILD -> $JAR_RUN"
|
||||
ls -lh "$JAR_RUN" | tee -a "$LOG_FILE"
|
||||
log_tee "完成。需要重启进程请执行: ./backend-restart.sh"
|
||||
58
scripts/backend-restart.sh
Executable file
58
scripts/backend-restart.sh
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env bash
|
||||
# 须用 bash 执行;若误用 sh/dash 会自动改用 bash 再跑一遍
|
||||
[ -n "${BASH_VERSION:-}" ] || exec /usr/bin/env bash "$0" ${1+"$@"}
|
||||
# 重启 Java 后端 chat_web_yj.jar(与 start_all.sh 一致)
|
||||
# 日志:gangyan/logs/backend.log
|
||||
# 勿在此加 -Dspring.datasource*:与 application-local.yml 打架易连错库。
|
||||
# 若 jar 未重打、内嵌 yml 仍是远程库,必须依赖 backend/application-local.yml(含完整 spring 数据源)。
|
||||
set -u
|
||||
source "$(cd "$(dirname "$0")" && pwd)/common-restart.sh"
|
||||
# 默认 backend.log;若曾被 root 创建导致当前用户不可写,则改用同目录 backend-<用户>.log(仍在 gangyan/logs 下)
|
||||
LOG_FILE="$LOG_DIR/backend.log"
|
||||
if ! ( umask 022; : >>"$LOG_FILE" ) 2>/dev/null; then
|
||||
ALT="$LOG_DIR/backend-$(id -un).log"
|
||||
if ( umask 022; : >>"$ALT" ) 2>/dev/null; then
|
||||
LOG_FILE="$ALT"
|
||||
log_tee "注意: $LOG_DIR/backend.log 不可写(多为 root 遗留),已改用 $LOG_FILE"
|
||||
log_tee "修复后可统一回 backend.log: sudo chown $(id -un):$(id -gn) \"$LOG_DIR/backend.log\" 或 sudo rm -f \"$LOG_DIR/backend.log\""
|
||||
else
|
||||
mkdir -p "${HOME}/.gangyan/logs"
|
||||
LOG_FILE="${HOME}/.gangyan/logs/backend-restart.log"
|
||||
log_tee "注意: gangyan/logs 不可写,Java 日志暂存: $LOG_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
|
||||
log_tee "======== 停止 chat_web_yj.jar ========"
|
||||
pkill -f "chat_web_yj.jar" 2>/dev/null && log_tee "已发送停止信号" || log_tee "未找到运行中的进程"
|
||||
sleep 2
|
||||
|
||||
log_tee "======== 启动 chat_web_yj.jar ========"
|
||||
cd "$GANGYAN_ROOT/backend"
|
||||
LOCAL_CFG="$GANGYAN_ROOT/backend/application-local.yml"
|
||||
EXTRA_JAVA_ARGS=()
|
||||
if [ -f "$LOCAL_CFG" ]; then
|
||||
log_tee "加载本地配置: $LOCAL_CFG"
|
||||
EXTRA_JAVA_ARGS=(-Dspring.config.additional-location="file:${LOCAL_CFG}")
|
||||
fi
|
||||
nohup java -jar \
|
||||
-Xms512m -Xmx2048m \
|
||||
"${EXTRA_JAVA_ARGS[@]}" \
|
||||
-Dspring.profiles.active=yj \
|
||||
chat_web_yj.jar >> "$LOG_FILE" 2>&1 &
|
||||
STARTED_PID=$!
|
||||
log_tee "已后台启动,PID=$STARTED_PID"
|
||||
log_tee "Java 标准输出/错误写入: $LOG_FILE"
|
||||
sleep 3
|
||||
if kill -0 "$STARTED_PID" 2>/dev/null; then
|
||||
if command -v ss >/dev/null 2>&1 && ss -tln 2>/dev/null | grep -q ':8099'; then
|
||||
log_tee "自检: 进程存活且 8099 已监听(后端已就绪或即将就绪)"
|
||||
else
|
||||
log_tee "自检: 进程存活,但 8099 尚未监听(可能仍在启动;若 10 秒后仍无,请 tail 上面日志路径)"
|
||||
fi
|
||||
else
|
||||
log_tee "自检失败: 进程已退出。请查看日志末尾:"
|
||||
tail -n 40 "$LOG_FILE" 2>/dev/null | while IFS= read -r line || [ -n "$line" ]; do log_line "$line"; done
|
||||
fi
|
||||
13
scripts/common-restart.sh
Executable file
13
scripts/common-restart.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
# 被各 *-restart.sh source,勿单独执行
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
GANGYAN_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
LOG_DIR="$GANGYAN_ROOT/logs"
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
log_line() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
|
||||
}
|
||||
|
||||
log_tee() {
|
||||
log_line "$@" | tee -a "$LOG_FILE"
|
||||
}
|
||||
29
scripts/frontend-restart.sh
Executable file
29
scripts/frontend-restart.sh
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
# 须用 bash 执行;若误用 sh/dash 会自动改用 bash 再跑一遍
|
||||
[ -n "${BASH_VERSION:-}" ] || exec /usr/bin/env bash "$0" ${1+"$@"}
|
||||
# 重启前端 vite(npm run dev);按 chat_web_project 使用的端口释放(默认读 .env 中 VITE_GLOB_FRONT_PORT)
|
||||
# 日志:gangyan/logs/frontend.log
|
||||
set -u
|
||||
source "$(cd "$(dirname "$0")" && pwd)/common-restart.sh"
|
||||
LOG_FILE="$LOG_DIR/frontend.log"
|
||||
|
||||
FRONT_ENV="$GANGYAN_ROOT/chat_web_front/.env"
|
||||
FRONT_PORT=3000
|
||||
if [ -f "$FRONT_ENV" ]; then
|
||||
_p=$(grep -E '^[[:space:]]*VITE_GLOB_FRONT_PORT=' "$FRONT_ENV" | head -1 | cut -d= -f2 | tr -d '\r"[:space:]')
|
||||
[ -n "${_p:-}" ] && FRONT_PORT="$_p"
|
||||
fi
|
||||
|
||||
log_tee "======== 停止前端(端口 $FRONT_PORT)========"
|
||||
for pid in $(lsof -ti :"$FRONT_PORT" -sTCP:LISTEN 2>/dev/null || true); do
|
||||
kill -TERM "$pid" 2>/dev/null && log_tee "TERM pid=$pid" || true
|
||||
done
|
||||
sleep 2
|
||||
for pid in $(lsof -ti :"$FRONT_PORT" -sTCP:LISTEN 2>/dev/null || true); do
|
||||
kill -KILL "$pid" 2>/dev/null && log_tee "KILL pid=$pid" || true
|
||||
done
|
||||
|
||||
log_tee "======== 启动 npm run dev ========"
|
||||
cd "$GANGYAN_ROOT/chat_web_front"
|
||||
nohup npm run dev >> "$LOG_FILE" 2>&1 &
|
||||
log_tee "已后台启动,PID=$! ,端口约 $FRONT_PORT ,日志: $LOG_FILE"
|
||||
157
scripts/langchain-restart.sh
Executable file
157
scripts/langchain-restart.sh
Executable file
@@ -0,0 +1,157 @@
|
||||
#!/usr/bin/env bash
|
||||
# 须用 bash 执行;若误用 sh/dash 会自动改用 bash 再跑一遍
|
||||
[ -n "${BASH_VERSION:-}" ] || exec /usr/bin/env bash "$0" ${1+"$@"}
|
||||
# 重启 langchain-chat(startup.py --all-api,与 start_all.sh 一致)
|
||||
# 日志:gangyan/logs/langchain-chat.log
|
||||
set -u
|
||||
source "$(cd "$(dirname "$0")" && pwd)/common-restart.sh"
|
||||
LOG_FILE="$LOG_DIR/langchain-chat.log"
|
||||
TRIM_LOG="$LOG_DIR/log-trim.log"
|
||||
|
||||
CONDA_SH="/opt/software/miniconda3/etc/profile.d/conda.sh"
|
||||
LC_ROOT="$GANGYAN_ROOT/langchain-chat"
|
||||
|
||||
# 与 configs/server_config.py 一致,用于旧进程未退出时按端口释放
|
||||
LANGCHAIN_LISTEN_PORTS=(7861 20000 20101 20002)
|
||||
|
||||
_kill_by_listen_ports() {
|
||||
local port pid
|
||||
for port in "${LANGCHAIN_LISTEN_PORTS[@]}"; do
|
||||
for pid in $(lsof -ti :"$port" -sTCP:LISTEN 2>/dev/null || true); do
|
||||
kill -TERM "$pid" 2>/dev/null && log_tee "按端口 ${port} TERM PID=${pid}"
|
||||
done
|
||||
done
|
||||
sleep 2
|
||||
for port in "${LANGCHAIN_LISTEN_PORTS[@]}"; do
|
||||
for pid in $(lsof -ti :"$port" -sTCP:LISTEN 2>/dev/null || true); do
|
||||
kill -KILL "$pid" 2>/dev/null && log_tee "按端口 ${port} KILL PID=${pid}"
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
# 用 ss 判断端口是否在监听。仅用 lsof 会漏掉 root 监听的端口(非 root 看不到 PID),
|
||||
# 会误判为已释放并再次启动,导致 [Errno 98] address already in use。
|
||||
_langchain_ports_still_listen() {
|
||||
local port
|
||||
for port in "${LANGCHAIN_LISTEN_PORTS[@]}"; do
|
||||
if ss -tln 2>/dev/null | grep -qE ":${port}[[:space:]]"; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_sudo_fuser_kill_ports() {
|
||||
command -v sudo >/dev/null 2>&1 || return 1
|
||||
if ! sudo -n true 2>/dev/null; then
|
||||
log_tee "提示: 相关端口仍被占用(可能是 root 启动的进程)。当前用户无法用 lsof 看到其 PID。"
|
||||
log_tee "请在本机执行其一: sudo bash $0 或 sudo fuser -k 7861/tcp 20000/tcp 20101/tcp 20002/tcp"
|
||||
return 1
|
||||
fi
|
||||
local port
|
||||
for port in "${LANGCHAIN_LISTEN_PORTS[@]}"; do
|
||||
if ss -tln 2>/dev/null | grep -qE ":${port}[[:space:]]"; then
|
||||
sudo -n fuser -k "${port}/tcp" 2>/dev/null && log_tee "sudo fuser -k ${port}/tcp"
|
||||
fi
|
||||
done
|
||||
sleep 2
|
||||
return 0
|
||||
}
|
||||
|
||||
_stop_langchain() {
|
||||
log_tee "======== 停止 langchain-chat ========"
|
||||
|
||||
# 多种命令行形式(-a / --all-api、conda 路径、直接 python)
|
||||
for pat in \
|
||||
"/opt/software/miniconda3/envs/langchain-chat/bin/python"'.''*'"startup.py" \
|
||||
"conda run -n langchain-chat"'.''*'"startup.py" \
|
||||
"python"'.''*'"startup.py --all-api" \
|
||||
"python"'.''*'"startup.py -a"
|
||||
do
|
||||
if pkill -f "$pat" 2>/dev/null; then
|
||||
log_tee "pkill 已匹配并发送信号: $pat"
|
||||
fi
|
||||
done
|
||||
|
||||
# cwd 在 langchain-chat 且命令行含 startup.py(兜底)
|
||||
while read -r pid; do
|
||||
[ -z "${pid:-}" ] && continue
|
||||
[ ! -d "/proc/$pid" ] && continue
|
||||
local cwd cmdl
|
||||
cwd=$(readlink -f "/proc/$pid/cwd" 2>/dev/null || true)
|
||||
cmdl=$(tr '\0' ' ' <"/proc/$pid/cmdline" 2>/dev/null || true)
|
||||
if [[ "$cmdl" == *startup.py* ]] && [[ "$cwd" == "$LC_ROOT" ]]; then
|
||||
kill -TERM "$pid" 2>/dev/null && log_tee "按 cwd+argv TERM PID=$pid"
|
||||
fi
|
||||
done < <(pgrep -f 'startup\.py' 2>/dev/null || true)
|
||||
|
||||
sleep 2
|
||||
|
||||
# pkill 未匹配到旧进程时,端口仍可能被旧实例占用(含 root 启动、非 root 无法用 lsof 杀)
|
||||
if _langchain_ports_still_listen; then
|
||||
log_tee "langchain 相关端口仍监听 (7861/20000/20101/20002),按 lsof 可见 PID 清理…"
|
||||
_kill_by_listen_ports
|
||||
else
|
||||
log_tee "相关端口已释放,跳过端口强杀"
|
||||
fi
|
||||
|
||||
if _langchain_ports_still_listen; then
|
||||
log_tee "端口仍被占用,尝试免密 sudo fuser 清理…"
|
||||
_sudo_fuser_kill_ports || true
|
||||
fi
|
||||
|
||||
local _w=0
|
||||
while _langchain_ports_still_listen && [ "$_w" -lt 30 ]; do
|
||||
sleep 1
|
||||
_w=$((_w + 1))
|
||||
done
|
||||
|
||||
if _langchain_ports_still_listen; then
|
||||
log_tee "错误: 7861/20000/20101/20002 仍有端口在监听,无法安全启动第二个实例。"
|
||||
log_tee "请先释放端口后再执行本脚本(见上方 sudo 提示)。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
}
|
||||
|
||||
_stop_langchain
|
||||
|
||||
# 停止旧的日志裁剪守护(避免重复多开)
|
||||
pkill -f "log-trim-daemon\.sh --file ${LOG_FILE}" 2>/dev/null || true
|
||||
|
||||
log_tee "======== 启动 langchain-chat (--all-api) ========"
|
||||
if [ ! -f "$CONDA_SH" ]; then
|
||||
log_tee "错误: 未找到 $CONDA_SH"
|
||||
exit 1
|
||||
fi
|
||||
# shellcheck source=/dev/null
|
||||
source "$CONDA_SH"
|
||||
conda activate langchain-chat
|
||||
cd "$LC_ROOT"
|
||||
export PYTHONPATH="$LC_ROOT"
|
||||
# PDF 预览与 kb_config.PDF_CONVERT_KB_ROOT 一致(地址归一化在 Python 内完成)
|
||||
export PDF_CONVERT_KB_ROOT="${PDF_CONVERT_KB_ROOT:-$LC_ROOT/knowledge_base}"
|
||||
# 明确使用可请求的地址(:- 无法覆盖已设置的 0.0.0.0,此处强制纠正)
|
||||
if [[ "${PDF_CONVERT_API_URL:-}" == *0.0.0.0* ]] || [[ -z "${PDF_CONVERT_API_URL:-}" ]]; then
|
||||
export PDF_CONVERT_API_URL="http://127.0.0.1:6006/convert/"
|
||||
fi
|
||||
# 避免旧 .pyc 仍含硬编码的 0.0.0.0:6006
|
||||
rm -f "$LC_ROOT/configs/__pycache__/kb_config."*.pyc 2>/dev/null || true
|
||||
rm -f "$LC_ROOT/server/knowledge_base/__pycache__/file_converter."*.pyc 2>/dev/null || true
|
||||
rm -f "$LC_ROOT/server/knowledge_base/__pycache__/cleanpdf."*.pyc 2>/dev/null || true
|
||||
rm -f "$LC_ROOT/server/knowledge_base/__pycache__/pdf_convert_url."*.pyc 2>/dev/null || true
|
||||
|
||||
# 控制日志文件总大小(保留最后 5MB,避免 langchain-chat.log 无限增长)
|
||||
nohup bash "$GANGYAN_ROOT/scripts/log-trim-daemon.sh" --file "$LOG_FILE" --max-mb 5 --interval-sec 3 >> "$TRIM_LOG" 2>&1 &
|
||||
log_tee "已启动日志裁剪守护,日志: $TRIM_LOG"
|
||||
|
||||
nohup python startup.py --all-api >> "$LOG_FILE" 2>&1 &
|
||||
log_tee "已后台启动,PID=$! ,API 约 7861 ,日志: $LOG_FILE"
|
||||
|
||||
# 本地 PDF 预览依赖的转换微服务(:6006);未监听时再启动
|
||||
if ! ss -tln 2>/dev/null | grep -qE ':6006[[:space:]]'; then
|
||||
bash "$GANGYAN_ROOT/scripts/pdf-convert-service.sh" >> "$LOG_DIR/pdf-convert-service.log" 2>&1 || log_tee "提示: pdf-convert-service 启动失败,见 $LOG_DIR/pdf-convert-service.log"
|
||||
else
|
||||
log_tee "pdf-convert-service 端口 6006 已在监听,跳过"
|
||||
fi
|
||||
59
scripts/log-trim-daemon.sh
Executable file
59
scripts/log-trim-daemon.sh
Executable file
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env bash
|
||||
# Keep a log file capped by trimming from the front.
|
||||
# Usage:
|
||||
# ./log-trim-daemon.sh --file /path/to/app.log --max-mb 5 --interval-sec 3
|
||||
set -euo pipefail
|
||||
|
||||
FILE=""
|
||||
MAX_MB=5
|
||||
INTERVAL_SEC=3
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--file) FILE="${2:-}"; shift 2 ;;
|
||||
--max-mb) MAX_MB="${2:-}"; shift 2 ;;
|
||||
--interval-sec) INTERVAL_SEC="${2:-}"; shift 2 ;;
|
||||
-h|--help)
|
||||
echo "Usage: $0 --file PATH [--max-mb 5] [--interval-sec 3]"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown arg: $1" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "${FILE}" ]; then
|
||||
echo "Missing --file" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
MAX_BYTES=$((MAX_MB * 1024 * 1024))
|
||||
TMP="${FILE}.trimtmp.$$"
|
||||
LOCK="${FILE}.trimlock"
|
||||
|
||||
mkdir -p "$(dirname "$FILE")"
|
||||
touch "$FILE" 2>/dev/null || true
|
||||
|
||||
while true; do
|
||||
if [ -f "$FILE" ]; then
|
||||
size=$(stat -c%s "$FILE" 2>/dev/null || echo 0)
|
||||
if [ "${size:-0}" -gt "$MAX_BYTES" ]; then
|
||||
# Keep only the last MAX_BYTES bytes.
|
||||
# IMPORTANT: do NOT replace the file inode (mv),否则 tail -f/编辑器可能还在看旧 inode,
|
||||
# 会出现“日志不更新/看不到最新内容”的错觉。这里用 copy+truncate 保持 inode 不变。
|
||||
(
|
||||
flock -w 2 9 || exit 0
|
||||
tail -c "$MAX_BYTES" "$FILE" > "$TMP" 2>/dev/null || true
|
||||
# 覆盖写回同一文件(inode 不变)
|
||||
if [ -s "$TMP" ]; then
|
||||
cat "$TMP" > "$FILE" 2>/dev/null || true
|
||||
fi
|
||||
rm -f "$TMP" 2>/dev/null || true
|
||||
) 9>"$LOCK" || true
|
||||
fi
|
||||
fi
|
||||
sleep "$INTERVAL_SEC"
|
||||
done
|
||||
|
||||
14
scripts/milvus-restart.sh
Executable file
14
scripts/milvus-restart.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
# 须用 bash 执行;若误用 sh/dash 会自动改用 bash 再跑一遍
|
||||
[ -n "${BASH_VERSION:-}" ] || exec /usr/bin/env bash "$0" ${1+"$@"}
|
||||
# 重启 Milvus(docker compose 目录:gangyan/milvus)
|
||||
# 日志:gangyan/logs/milvus.log
|
||||
set -u
|
||||
source "$(cd "$(dirname "$0")" && pwd)/common-restart.sh"
|
||||
LOG_FILE="$LOG_DIR/milvus.log"
|
||||
|
||||
log_tee "======== 重启 Milvus ========"
|
||||
cd "$GANGYAN_ROOT/milvus"
|
||||
docker compose restart 2>&1 | tee -a "$LOG_FILE" || docker compose up -d 2>&1 | tee -a "$LOG_FILE"
|
||||
log_tee "完成。docker compose ps ->"
|
||||
docker compose ps 2>&1 | tee -a "$LOG_FILE"
|
||||
14
scripts/mysql-restart.sh
Executable file
14
scripts/mysql-restart.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
# 须用 bash 执行;若误用 sh/dash 会自动改用 bash 再跑一遍
|
||||
[ -n "${BASH_VERSION:-}" ] || exec /usr/bin/env bash "$0" ${1+"$@"}
|
||||
# 重启 MySQL 8.4(docker compose 目录:gangyan/mysql/mysql-8.4.4)
|
||||
# 日志:gangyan/logs/mysql.log
|
||||
set -u
|
||||
source "$(cd "$(dirname "$0")" && pwd)/common-restart.sh"
|
||||
LOG_FILE="$LOG_DIR/mysql.log"
|
||||
|
||||
log_tee "======== 重启 MySQL ========"
|
||||
cd "$GANGYAN_ROOT/mysql/mysql-8.4.4"
|
||||
docker compose restart 2>&1 | tee -a "$LOG_FILE" || docker compose up -d 2>&1 | tee -a "$LOG_FILE"
|
||||
log_tee "完成。docker compose ps ->"
|
||||
docker compose ps 2>&1 | tee -a "$LOG_FILE"
|
||||
49
scripts/pdf-convert-service.sh
Executable file
49
scripts/pdf-convert-service.sh
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
# 本地 PDF→Markdown 微服务(与 langchain file_converter.pdf_to_html 约定一致,默认 :6006)
|
||||
# 依赖 conda 环境 langchain-chat(含 fastapi、uvicorn、PyMuPDF)
|
||||
[ -n "${BASH_VERSION:-}" ] || exec /usr/bin/env bash "$0" ${1+"$@"}
|
||||
set -u
|
||||
source "$(cd "$(dirname "$0")" && pwd)/common-restart.sh"
|
||||
LOG_FILE="$LOG_DIR/pdf-convert-service.log"
|
||||
LC_ROOT="$GANGYAN_ROOT/langchain-chat"
|
||||
CONDA_SH="/opt/software/miniconda3/etc/profile.d/conda.sh"
|
||||
|
||||
log_line() {
|
||||
local s="[$(date '+%Y-%m-%d %H:%M:%S')] $*"
|
||||
echo "$s" >> "$LOG_FILE"
|
||||
echo "$s"
|
||||
}
|
||||
|
||||
log_line "======== 停止 pdf-convert-service (6006) ========"
|
||||
pkill -f "uvicorn.*pdf_convert_service\.app:app" 2>/dev/null || true
|
||||
sleep 1
|
||||
if command -v lsof >/dev/null 2>&1; then
|
||||
for pid in $(lsof -ti :6006 -sTCP:LISTEN 2>/dev/null || true); do
|
||||
kill -TERM "$pid" 2>/dev/null && log_line "TERM pid=$pid :6006"
|
||||
done
|
||||
sleep 1
|
||||
for pid in $(lsof -ti :6006 -sTCP:LISTEN 2>/dev/null || true); do
|
||||
kill -KILL "$pid" 2>/dev/null && log_line "KILL pid=$pid :6006"
|
||||
done
|
||||
fi
|
||||
|
||||
log_line "======== 启动 pdf-convert-service ========"
|
||||
if [ ! -f "$CONDA_SH" ]; then
|
||||
log_line "错误: 未找到 $CONDA_SH"
|
||||
exit 1
|
||||
fi
|
||||
# shellcheck source=/dev/null
|
||||
source "$CONDA_SH"
|
||||
conda activate langchain-chat
|
||||
cd "$LC_ROOT"
|
||||
export PYTHONPATH="$LC_ROOT"
|
||||
export PDF_CONVERT_KB_ROOT="${PDF_CONVERT_KB_ROOT:-$LC_ROOT/knowledge_base}"
|
||||
export PDF_CONVERT_HOST="${PDF_CONVERT_HOST:-127.0.0.1}"
|
||||
export PDF_CONVERT_PORT="${PDF_CONVERT_PORT:-6006}"
|
||||
|
||||
nohup python -m uvicorn pdf_convert_service.app:app \
|
||||
--host "$PDF_CONVERT_HOST" --port "$PDF_CONVERT_PORT" \
|
||||
>> "$LOG_FILE" 2>&1 &
|
||||
log_line "已后台启动 PID=$! 监听 ${PDF_CONVERT_HOST}:${PDF_CONVERT_PORT}"
|
||||
log_line "日志: $LOG_FILE KB_ROOT=$PDF_CONVERT_KB_ROOT"
|
||||
log_line "健康检查: curl -sS http://${PDF_CONVERT_HOST}:${PDF_CONVERT_PORT}/health"
|
||||
18
scripts/redis-restart.sh
Executable file
18
scripts/redis-restart.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
# 须用 bash 执行;若误用 sh/dash 会自动改用 bash 再跑一遍
|
||||
[ -n "${BASH_VERSION:-}" ] || exec /usr/bin/env bash "$0" ${1+"$@"}
|
||||
# 重启 Redis 容器 redis-server;若不存在则创建(与 start_all.sh 一致)
|
||||
# 日志:gangyan/logs/redis.log
|
||||
set -u
|
||||
source "$(cd "$(dirname "$0")" && pwd)/common-restart.sh"
|
||||
LOG_FILE="$LOG_DIR/redis.log"
|
||||
|
||||
log_tee "======== 重启 Redis ========"
|
||||
if docker ps -a --format '{{.Names}}' | grep -qx 'redis-server'; then
|
||||
docker restart redis-server 2>&1 | tee -a "$LOG_FILE"
|
||||
else
|
||||
log_tee "容器不存在,尝试创建..."
|
||||
docker run -d --name redis-server -p 6379:6379 redis:7-alpine 2>&1 | tee -a "$LOG_FILE"
|
||||
fi
|
||||
log_tee "完成。docker ps redis-server ->"
|
||||
docker ps --filter name=redis-server 2>&1 | tee -a "$LOG_FILE"
|
||||
Reference in New Issue
Block a user