diff --git a/.gitea/workflows/deploy.yaml b/.gitea/workflows/deploy.yaml index 1eb28608..60c17d96 100644 --- a/.gitea/workflows/deploy.yaml +++ b/.gitea/workflows/deploy.yaml @@ -379,8 +379,18 @@ jobs: sudo chown -R "${DEPLOY_USER}:${DEPLOY_GROUP}" "${LIVE}" 2>/dev/null || true + # Next.js prefers an already-set process PORT over .env. PM2 may still + # have PORT=3000 from an older start, while .env (and nginx) expect 3002. + # Export PORT before reload so --update-env aligns the running process. + DEPLOY_PORT="$(grep -E '^[[:space:]]*PORT=' "${LIVE}/.env" 2>/dev/null | tail -1 | cut -d= -f2- || true)" + DEPLOY_PORT="$(printf '%s' "${DEPLOY_PORT}" | tr -cd '0-9')" + DEPLOY_PORT="${DEPLOY_PORT:-3002}" + export PORT="${DEPLOY_PORT}" + echo "PM2/health PORT=${PORT}" + echo "Starting PM2 (zero-downtime reload)..." - pm2 reload next --update-env || pm2 start next --update-env + cd "${LIVE}" + pm2 reload next --update-env || pm2 start pnpm --name next --update-env -- start sleep 3 if ! pm2 show next 2>/dev/null | grep -q 'online'; then @@ -389,23 +399,24 @@ jobs: exit 1 fi - DEPLOY_PORT="$(grep -E '^[[:space:]]*PORT=.+' "${LIVE}/.env" 2>/dev/null | cut -d= -f2 | tr -d '"' || echo '3002')" - echo "Waiting for HTTP health check on port ${DEPLOY_PORT}..." - HEALTH_URL="${DEPLOY_HEALTH_URL:-http://127.0.0.1:${DEPLOY_PORT}/api/health}" + echo "Waiting for HTTP health check on port ${PORT}..." + HEALTH_URL="${DEPLOY_HEALTH_URL:-http://127.0.0.1:${PORT}/api/health}" HEALTH_OK=0 - for i in $(seq 1 15); do + for i in $(seq 1 20); do BODY="$(curl -sf --max-time 5 "${HEALTH_URL}" 2>/dev/null || true)" if echo "${BODY}" | grep -q '"database":true'; then echo "Health OK (${HEALTH_URL})" HEALTH_OK=1 break fi - echo "Health attempt ${i}/15 failed, retrying..." + echo "Health attempt ${i}/20 failed (body=${BODY:-}), retrying..." sleep 2 done if [ "${HEALTH_OK}" != "1" ]; then echo "ERROR: Health check failed after deploy (${HEALTH_URL})" >&2 echo "Last body: ${BODY:-}" >&2 + echo "PM2 env PORT (should match .env):" >&2 + pm2 env 0 2>/dev/null | grep -E '^PORT=' >&2 || true pm2 logs next --lines 40 --nostream >&2 || true exit 1 fi diff --git a/package.json b/package.json index 2a30d3f6..244e789f 100644 --- a/package.json +++ b/package.json @@ -87,6 +87,7 @@ "dotenv": "^17.4.2", "husky": "^9.1.7", "knip": "^6.29.0", + "lint-staged": "^17.2.0", "pino-pretty": "^13.1.3", "postcss": "^8.5.25", "prisma": "^7.9.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 824622fc..3eea03be 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -180,6 +180,9 @@ importers: knip: specifier: ^6.29.0 version: 6.29.0 + lint-staged: + specifier: ^17.2.0 + version: 17.2.0 pino-pretty: specifier: ^13.1.3 version: 13.1.3 @@ -3538,6 +3541,11 @@ packages: resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} engines: {node: '>= 12.0.0'} + lint-staged@17.2.0: + resolution: {integrity: sha512-FchGnFe4i4B1C/a35SPU9bNGPEHSC1+1iV0plLjzBmKVe9klZrlRfSgK6Cw4VeHyqOXbJUXP0vON61uRftNQ0A==} + engines: {node: '>=22.22.1'} + hasBin: true + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -4207,6 +4215,10 @@ packages: std-env@4.2.0: resolution: {integrity: sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==} + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -7420,6 +7432,14 @@ snapshots: lightningcss-win32-arm64-msvc: 1.33.0 lightningcss-win32-x64-msvc: 1.33.0 + lint-staged@17.2.0: + dependencies: + picomatch: 4.0.5 + string-argv: 0.3.2 + tinyexec: 1.2.4 + optionalDependencies: + yaml: 2.9.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -8121,6 +8141,8 @@ snapshots: std-env@4.2.0: {} + string-argv@0.3.2: {} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0