diff --git a/jenkins/流水线配置/lessie-email.conf b/jenkins/流水线配置/lessie-email.conf index 1225423..519f749 100644 --- a/jenkins/流水线配置/lessie-email.conf +++ b/jenkins/流水线配置/lessie-email.conf @@ -32,18 +32,20 @@ pipeline { stage('同步文件') { steps { sh """ - rsync -avz --exclude '.venv' ${WORKSPACE}/ ${REMOTE_HOST}:${REMOTE_PROJECT_PATH}/ + rsync -avz --exclude '.venv' --exclude '.git' ${WORKSPACE}/ ${REMOTE_HOST}:${REMOTE_PROJECT_PATH}/ """ } } - // stage('下线服务') { - // steps { - // sh """ - - // """ - // } - // } + stage('下线服务') { + steps { + sh """ + ssh ${REMOTE_HOST} ' + sh /data/sh/kill_lessie_emial.sh + ' + """ + } + } stage('安装 & 启动服务') { steps { @@ -51,24 +53,64 @@ pipeline { ssh ${REMOTE_HOST} ' cd ${REMOTE_PROJECT_PATH} uv sync + source .venv/bin/activate TIMESTAMP=\$(date +"%Y%m%d_%H%M%S") LOGFILE="${REMOTE_PROJECT_PATH}/logs/lessie_email_\${TIMESTAMP}.log" - nohup ENV=s4 uv run uvicorn app.main:app --port 8031 > "\$LOGFILE" 2>&1 & - ln -sf "\$LOGFILE" {REMOTE_PROJECT_PATH}/logs/lessie_email_latest.log + nohup env ENV=s4 uv run uvicorn app.main:app --host 0.0.0.0 --port 8031 > "\$LOGFILE" 2>&1 & + ln -sf "\$LOGFILE" ${REMOTE_PROJECT_PATH}/logs/lessie_email_latest.log ' """ } } - // stage('检查服务') { - // steps { - // sh """ - // ssh ${REMOTE_HOST} ' + stage('检查服务') { + steps { + script { + def checkResult = sh returnStatus: true, script: """ + ssh ${REMOTE_HOST} ' + set -e + LOG_LATEST="${REMOTE_PROJECT_PATH}/logs/lessie_email_latest.log" + + # 1. 检查端口是否监听(用 ss 原生过滤,精准可靠) + echo "【检查 1/3】检测端口 8031 是否监听..." + if ! ss -tnl \'sport = :8031\' >/dev/null 2>&1; then + echo "端口 8031 未监听!" + # 显示当前监听状态供排查 + echo "当前监听情况:" + ss -tnl | grep -E ":(8031|LISTEN)" + exit 1 + fi + echo "端口 8031 正在监听" - // ' - // """ - // } - // } + # 2. 检查进程是否存在 + echo "【检查 2/3】检测 uvicorn 进程是否存活..." + if ! pgrep -f "uvicorn.*app.main:app" >/dev/null; then + echo "未找到 uvicorn 进程!" + exit 1 + fi + echo "uvicorn 进程存在" + + # 3. 显示最新日志(最后 20 行) + echo "【检查 3/3】显示启动日志(最后 20 行)..." + echo "────────────────────────────" + if [ -f "\$LOG_LATEST" ]; then + tail -n 20 "\$LOG_LATEST" + else + echo "日志文件不存在:\$LOG_LATEST" + exit 1 + fi + echo "────────────────────────────" + echo "服务启动成功!" + ' + """ + + if (checkResult != 0) { + error "服务启动检查失败!请查看上述日志排查问题。" + } + } + } + } + } post { success { diff --git a/jenkins/流水线配置/lessie-next-prod-web copy.conf b/jenkins/流水线配置/lessie-next-prod-web copy.conf new file mode 100644 index 0000000..40bd653 --- /dev/null +++ b/jenkins/流水线配置/lessie-next-prod-web copy.conf @@ -0,0 +1,90 @@ +pipeline { + agent any + + parameters { + gitParameter( + branchFilter: 'origin/(.*)', + defaultValue: 'dev', + name: 'GIT_BRANCH', + type: 'PT_BRANCH_TAG', + selectedValue: 'DEFAULT', + sortMode: 'NONE', + description: '选择代码分支: ', + quickFilterEnabled: true, + tagFilter: '*', + listSize: "5" + ) + } + + environment { + REMOTE_HOST = '43.130.56.138' + REMOTE_HOST_B = '43.153.21.64' + REMOTE_PROJECT_PATH = '/data/webapps/lessie-next' + } + + stages { + stage('Checkout 代码') { + steps { + git branch: "${params.GIT_BRANCH}", credentialsId: 'fly_gitlab_auth', url: 'http://172.24.16.20/web/lessie-next.git' + } + } + + stage('同步') { + steps { + sh """ + rsync -avz --delete --exclude='node_modules' ${WORKSPACE}/ ${REMOTE_HOST}:${REMOTE_PROJECT_PATH}/ + """ + } + } + + stage('安装启动A') { + steps { + sh """ + ssh ${REMOTE_HOST} ' + cd ${REMOTE_PROJECT_PATH} && + pm2 delete lessie-next || true && + pm2 list && + nvm use 22.21.1 && + npm install && + npm run build:prod && + pm2 start ecosystem.config.cjs --env production && + pm2 save + ' + """ + } + } + + stage('同步B') { + steps { + sh """ + rsync -avz --delete --exclude='node_modules' ${WORKSPACE}/ ${REMOTE_HOST_B}:${REMOTE_PROJECT_PATH}/ + """ + } + } + stage('安装启动B') { + steps { + sh """ + ssh ${REMOTE_HOST_B} ' + cd ${REMOTE_PROJECT_PATH} && + pm2 delete lessie-next || true && + pm2 list && + nvm use 22.21.1 && + npm install && + npm run build:prod && + pm2 start ecosystem.config.cjs --env production && + pm2 save + ' + """ + } + } + } + + post { + success { + echo '部署成功' + } + failure { + echo '部署失败,请检查日志' + } + } +} diff --git a/jenkins/流水线配置/lessie-next-test-web.conf b/jenkins/流水线配置/lessie-next-test-web.conf new file mode 100644 index 0000000..8f19523 --- /dev/null +++ b/jenkins/流水线配置/lessie-next-test-web.conf @@ -0,0 +1,66 @@ +pipeline { + agent any + + parameters { + gitParameter( + branchFilter: 'origin/(.*)', + defaultValue: 'dev', + name: 'GIT_BRANCH', + type: 'PT_BRANCH_TAG', + selectedValue: 'DEFAULT', + sortMode: 'NONE', + description: '选择代码分支: ', + quickFilterEnabled: true, + tagFilter: '*', + listSize: "5" + ) + } + + environment { + REMOTE_HOST = '192.168.70.15' + REMOTE_PROJECT_PATH = '/data/webapps/lessie-next' + } + + stages { + stage('Checkout 代码') { + steps { + git branch: "${params.GIT_BRANCH}", credentialsId: 'fly_gitlab_auth', url: 'http://172.24.16.20/web/lessie-next.git' + } + } + + stage('同步') { + steps { + sh """ + ssh ${REMOTE_HOST} 'mkdir -p ${REMOTE_PROJECT_PATH}' + rsync -avz --delete --exclude='node_modules' ${WORKSPACE}/ ${REMOTE_HOST}:${REMOTE_PROJECT_PATH}/ + """ + } + } + + stage('安装启动') { + steps { + sh """ + ssh ${REMOTE_HOST} ' + cd ${REMOTE_PROJECT_PATH} && + pm2 delete lessie-next || true && + pm2 list && + nvm use 22.21.1 && + npm install && + npm run build:test && + pm2 start ecosystem.config.cjs --env test && + pm2 save + ' + """ + } + } + } + + post { + success { + echo '部署成功' + } + failure { + echo '部署失败,请检查日志' + } + } +} diff --git a/jenkins/流水线配置/lessie-profile-test-web.conf b/jenkins/流水线配置/lessie-profile-test-web.conf index f39ed71..a068df6 100644 --- a/jenkins/流水线配置/lessie-profile-test-web.conf +++ b/jenkins/流水线配置/lessie-profile-test-web.conf @@ -47,7 +47,7 @@ pipeline { nvm use 22.21.1 && npm install && npm run build && - pm2 start ecosystem.config.cjs && + pm2 start ecosystem.config.cjs --env test && pm2 save ' """ diff --git a/nginx/lessie_official_web.conf b/nginx/lessie_official_web.conf index cf92423..7d25a53 100644 --- a/nginx/lessie_official_web.conf +++ b/nginx/lessie_official_web.conf @@ -3,9 +3,9 @@ upstream official_backend { server 10.0.0.15:3000; # 机器B的内网地址 } -upstream newofficial_backend { - server 10.0.0.5:3003; # 机器A的内网地址 - server 10.0.0.15:3003; # 机器B的内网地址 +upstream new_official_backend { + server 10.0.0.5:3003; + server 10.0.0.15:3003; } log_format official_log '$remote_addr - $remote_user [$time_local] ' @@ -54,14 +54,29 @@ server { access_log /data/tengine/logs/lessie.ai.access.log official_log; error_log /data/tengine/logs/lessie.ai.error.log; - - # 反向代理到后端服务器渲染的nxut项目端口(新框架的几个页面) - location ~ ^/(influencer-marketing|b2b-lead-generation|investor-scouting|recruiting|partnerships) { + # 1. 新框架的业务页面逻辑 + location ~ "^/([a-z]{2}(-[a-z]{2})?/)?(influencer-marketing|b2b-lead-generation|investor-scouting|recruiting|partnerships)" { proxy_pass http://new_official_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } + # 2. 静态资源分流 (核心逻辑) + location ~ ^/(_next/|__nuxt/|.*\.json) { + # 默认给老项目 (3000端口) + set $target_upstream http://official_backend; + + # 只有当来源页面 (Referer) 明确包含新项目的关键字时,才改发到 3003 + if ($http_referer ~* "(influencer-marketing|b2b-lead-generation|investor-scouting|recruiting|partnerships)") { + set $target_upstream http://new_official_backend; + } + + proxy_pass $target_upstream; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } # 反向代理到后端服务器渲染的nxut项目3000端口(老框架的完整页面) location / { @@ -69,9 +84,21 @@ server { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } - - # 禁止logo走缓存 + + location /video/ { + root /data/tengine/html/lessie_official; + expires 30d; + add_header Cache-Control "public"; + add_header Accept-Ranges bytes; + } + + # 禁止 logo 缓存(默认给用户方形) location = /favicon.svg { + # 判断 UA,如果是 Googlebot,改写路径 + if ($http_user_agent ~* "(Googlebot|Bingbot)") { + rewrite ^/favicon.svg$ /favicon-google.svg last; + } + proxy_pass http://official_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; @@ -81,11 +108,9 @@ server { add_header Expires 0 always; } - location = /favicon.ico { - proxy_pass http://official_backend; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - + # Googlebot 专用 favicon 文件(圆形图标) + location = /favicon-google.svg { + root /data/tengine/html/lessie_official; add_header Cache-Control "no-cache, no-store, must-revalidate" always; add_header Pragma "no-cache" always; add_header Expires 0 always; diff --git a/nginx/s4.jennie.im.conf b/nginx/s4.jennie.im.conf index 65b2269..b1c19ea 100644 --- a/nginx/s4.jennie.im.conf +++ b/nginx/s4.jennie.im.conf @@ -70,6 +70,30 @@ server { } } + # email-api 的代理配置 + location /email-api/ { + proxy_pass http://10.0.0.5:8031; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_buffering off; + proxy_cache off; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_request_buffering off; + + add_header 'Access-Control-Allow-Origin' "$http_origin" always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE' always; + add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,X-Requested-With,Accept,Origin' always; + + if ($request_method = OPTIONS ) { + return 204; + } + } + location /api/chat/stream { proxy_pass http://s4_jennie_im_backend;