set -euo pipefail repo_url="${REPO_URL:-http://gitadmin:12345678911@gitea:3000/gitadmin/signalscout-backend.git}" source_dir="/opt/signalscout-source" remote_dir="/opt/signalscout" release_dir="/opt/signalscout.release" public_ready_url="${PUBLIC_READY_URL:-}" python_bin="${PYTHON_BIN:-python3.9}" deploy_lock="/tmp/signalscout-backend-deploy.lock" # 同一时间只允许一个部署任务替换源码、虚拟环境和运行目录,避免并发构建互相删除文件。 exec 9>"${deploy_lock}" flock 9 # 服务器直接从 Gitea main 分支取代码,Jenkins和手动部署共享同一条发布路径。 if [ ! -d "${source_dir}/.git" ]; then rm -rf "${source_dir}" git clone --branch main "${repo_url}" "${source_dir}" else git -C "${source_dir}" remote set-url origin "${repo_url}" git -C "${source_dir}" fetch origin main git -C "${source_dir}" reset --hard origin/main fi if ! command -v "${python_bin}" >/dev/null 2>&1; then echo "Python runtime is required but ${python_bin} was not found" >&2 exit 1 fi # 源码目录先安装开发依赖并跑测试,测试通过后才生成发布目录。 rm -rf "${source_dir}/.venv" "${python_bin}" -m venv "${source_dir}/.venv" "${source_dir}/.venv/bin/python" -m ensurepip --upgrade "${source_dir}/.venv/bin/python" -m pip install -e "${source_dir}[dev]" "${source_dir}/.venv/bin/python" -B -m ruff check "${source_dir}" "${source_dir}/.venv/bin/python" -B -m pytest "${source_dir}" # 发布目录重新生成,避免把源码仓库、测试缓存或旧虚拟环境带入 systemd 运行目录。 rm -rf "${release_dir}" mkdir -p "${release_dir}" tar \ --exclude=.git \ --exclude=.venv \ --exclude=.pytest_cache \ --exclude=.ruff_cache \ --exclude=__pycache__ \ --exclude=*.pyc \ --exclude=.env \ --exclude=reports \ --exclude=logs \ -C "${source_dir}" \ -cf - . | tar -C "${release_dir}" -xf - # 服务配置以服务器当前 .env 为准;缺失时直接失败,避免 systemd 启动后才暴露为502。 if [ ! -f "${remote_dir}/.env" ]; then echo "signalscout backend .env is missing at ${remote_dir}/.env" >&2 exit 1 fi cp "${remote_dir}/.env" "${release_dir}/.env" "${python_bin}" -m venv "${release_dir}/.venv" "${release_dir}/.venv/bin/python" -m ensurepip --upgrade "${release_dir}/.venv/bin/python" -m pip install -e "${release_dir}" ( cd "${release_dir}" "${release_dir}/.venv/bin/python" -B -m alembic upgrade head "${release_dir}/.venv/bin/python" -B scripts/seed_topics.py ) rm -rf "${remote_dir}" mv "${release_dir}" "${remote_dir}" mkdir -p "${remote_dir}/logs" "${remote_dir}/reports" cp "${remote_dir}/deployment/systemd/signalscout.service" /etc/systemd/system/signalscout.service systemctl daemon-reload systemctl restart signalscout if ! systemctl is-active --quiet signalscout; then systemctl status signalscout --no-pager -l >&2 || true journalctl -u signalscout -n 120 --no-pager >&2 || true exit 1 fi # systemd启动成功后继续等待HTTP健康检查,确保API真实开始监听。 for attempt in $(seq 1 20); do if curl -fsS "http://127.0.0.1:8020/health" >/dev/null; then if [ -n "${public_ready_url}" ]; then curl -fsS "${public_ready_url}" >/dev/null fi echo "signalscout backend deploy ok" exit 0 fi sleep 1 done echo "signalscout backend health check failed" >&2 systemctl status signalscout --no-pager -l >&2 || true journalctl -u signalscout -n 120 --no-pager >&2 || true exit 1