#!/usr/bin/env bash set -euo pipefail APP_DIR="${APP_DIR:-/opt/dataops-platform}" ENV_FILE="${APP_ENV_FILE:-/etc/dataops-platform/dataops.env}" LOG_DIR="${APP_DIR}/logs" VENV_DIR="${APP_DIR}/venv" mkdir -p "${LOG_DIR}" if [[ -f "${ENV_FILE}" ]]; then if [[ ! -r "${ENV_FILE}" ]]; then echo "无法读取环境变量文件: ${ENV_FILE} (用户: $(id -un))" >&2 echo "请执行: sudo chown root:ubuntu ${ENV_FILE} && sudo chmod 640 ${ENV_FILE}" >&2 exit 1 fi set -a # shellcheck disable=SC1090 source <(sed 's/\r$//' "${ENV_FILE}" | sed '1s/^\xEF\xBB\xBF//') set +a fi if [[ -z "${DEEPSEEK_API_KEY:-}" && -z "${LLM_API_KEY:-}" ]]; then echo "[run_dataops] WARN: DEEPSEEK_API_KEY 未从 ${ENV_FILE} 加载" >&2 fi export FLASK_ENV="${FLASK_ENV:-production}" export APP_ENV_FILE="${ENV_FILE}" export APP_DIR="${APP_DIR:-/opt/dataops-platform}" export PYTHONPATH="${APP_DIR}${PYTHONPATH:+:${PYTHONPATH}}" LISTEN_HOST="${LISTEN_HOST:-0.0.0.0}" LISTEN_PORT="${LISTEN_PORT:-5500}" GUNICORN_WORKERS="${GUNICORN_WORKERS:-4}" GUNICORN_TIMEOUT="${GUNICORN_TIMEOUT:-120}" # 与 Flask ProductionConfig.PORT 保持一致 export PORT="${PORT:-${LISTEN_PORT}}" # 统一写入绝对路径,避免相对路径落到 APP_DIR 根目录 export LOG_DIR="${LOG_DIR:-${APP_DIR}/logs}" mkdir -p "${LOG_DIR}" if [[ -z "${LOG_FILE:-}" || "${LOG_FILE}" != /* ]]; then log_filename="${LOG_FILE:-flask_production.log}" log_filename="${log_filename##*/}" export LOG_FILE="${LOG_DIR}/${log_filename}" fi cd "${APP_DIR}" if [[ ! -x "${VENV_DIR}/bin/gunicorn" ]]; then echo "gunicorn 未安装: ${VENV_DIR}/bin/gunicorn" >&2 exit 1 fi echo "[run_dataops] binding ${LISTEN_HOST}:${LISTEN_PORT} workers=${GUNICORN_WORKERS} log=${LOG_FILE}" >&2 if [[ ! -f "${APP_DIR}/gunicorn_config.py" ]]; then echo "缺少 gunicorn 配置: ${APP_DIR}/gunicorn_config.py" >&2 exit 1 fi # 启动前验证 Flask 应用能正常加载(失败时错误写入 supervisor 日志) if ! "${VENV_DIR}/bin/python" -c "from app import create_app; create_app(); print('app bootstrap ok')" >&2; then echo "Flask 应用预检失败,请检查 ${ENV_FILE} 与依赖配置" >&2 exit 1 fi exec "${VENV_DIR}/bin/gunicorn" \ --config "${APP_DIR}/gunicorn_config.py" \ --bind "${LISTEN_HOST}:${LISTEN_PORT}" \ --workers "${GUNICORN_WORKERS}" \ --timeout "${GUNICORN_TIMEOUT}" \ --access-logfile "${LOG_DIR}/gunicorn_access.log" \ --error-logfile "${LOG_DIR}/gunicorn_error.log" \ --capture-output \ --enable-stdio-inheritance \ --log-level info \ wsgi:application