build: back #348
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Production CI/CD Pipeline for docs.plus | |
| # Zero-Downtime Deployment Strategy | |
| name: CI-Production | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| jobs: | |
| # ============================================================ | |
| # UPTIME KUMA - Independent pipeline (no dependencies) | |
| # ============================================================ | |
| build-uptime-kuma: | |
| name: π Deploy Uptime Kuma | |
| runs-on: prod.docs.plus | |
| if: contains(github.event.head_commit.message, 'build') && contains(github.event.head_commit.message, 'uptime-kuma') | |
| steps: | |
| - name: π¦ Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| clean: false | |
| - name: π Deploy Uptime Kuma | |
| run: make build_uptime_kuma | |
| # ============================================================ | |
| # FRONTEND - Build and deploy Next.js app with PM2 | |
| # Zero-downtime via PM2 reload (rolling restart) | |
| # ============================================================ | |
| build-front: | |
| name: π¨ Deploy Frontend | |
| runs-on: prod.docs.plus | |
| if: contains(github.event.head_commit.message, 'build') && contains(github.event.head_commit.message, 'front') | |
| steps: | |
| - name: π¦ Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| clean: false | |
| - name: π₯ Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - name: π₯ Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: π Ensure .env exists | |
| run: | | |
| if [ -f "../../../.env" ]; then | |
| cp ../../../.env packages/webapp/.env | |
| elif [ -f "../../.env" ]; then | |
| cp ../../.env packages/webapp/.env | |
| elif [ -f ".env" ]; then | |
| cp .env packages/webapp/.env | |
| fi | |
| continue-on-error: true | |
| - name: π Build & Deploy Frontend (Zero-Downtime) | |
| run: make build_front_production | |
| timeout-minutes: 15 | |
| - name: π©Ί Health check | |
| run: | | |
| echo "β³ Waiting for app to be ready..." | |
| sleep 15 | |
| # Retry health check up to 5 times | |
| for i in {1..5}; do | |
| if curl -f http://localhost:3001/api/health; then | |
| echo "β Frontend is healthy!" | |
| exit 0 | |
| fi | |
| echo "β³ Retry $i/5..." | |
| sleep 5 | |
| done | |
| echo "β Health check failed after 5 retries" | |
| exit 1 | |
| - name: π Post-deployment status | |
| if: always() | |
| run: | | |
| echo "π PM2 Status:" | |
| cd packages/webapp && bun run pm2 list | |
| echo "" | |
| echo "πΎ Memory Usage:" | |
| cd packages/webapp && bun run pm2 describe nextjs_production | grep -A 5 "memory" | |
| # ============================================================ | |
| # BACKEND - Build and deploy with Blue-Green strategy | |
| # Zero-downtime via Blue-Green deployment with Nginx | |
| # ============================================================ | |
| build-back: | |
| name: π§ Deploy Backend | |
| runs-on: prod.docs.plus | |
| if: contains(github.event.head_commit.message, 'build') && contains(github.event.head_commit.message, 'back') | |
| steps: | |
| - name: π¦ Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 1 | |
| clean: false | |
| - name: π₯ Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: latest | |
| - name: π₯ Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: π Ensure .env is available | |
| run: | | |
| if [ -f "../../../.env" ]; then | |
| cp ../../../.env packages/hocuspocus.server/.env | |
| elif [ -f "../../.env" ]; then | |
| cp ../../.env packages/hocuspocus.server/.env | |
| elif [ -f ".env" ]; then | |
| cp .env packages/hocuspocus.server/.env | |
| fi | |
| continue-on-error: true | |
| - name: π΅π’ Blue-Green Deployment | |
| run: make build_hocuspocus.server_prod | |
| timeout-minutes: 15 | |
| - name: π©Ί Verify deployment health | |
| run: | | |
| echo "β³ Verifying deployment health..." | |
| sleep 5 | |
| # Check if nginx is running | |
| if ! docker ps | grep -q "prod-nginx-docsplus"; then | |
| echo "β Nginx proxy not running!" | |
| exit 1 | |
| fi | |
| # Health check via nginx proxy | |
| for i in {1..10}; do | |
| if curl -f http://localhost:3001/health; then | |
| echo "β Backend is healthy!" | |
| break | |
| fi | |
| echo "β³ Health check attempt $i/10..." | |
| sleep 3 | |
| done | |
| - name: π Post-deployment status | |
| if: always() | |
| run: | | |
| echo "π Deployment Status:" | |
| make status_prod | |
| echo "" | |
| echo "π³ Docker Containers:" | |
| docker ps | grep docsplus || echo "No containers found" | |
| echo "" | |
| echo "π Container Health:" | |
| docker ps --format "table {{.Names}}\t{{.Status}}" | grep docsplus || echo "No containers found" | |
| - name: π Rollback on failure | |
| if: failure() | |
| run: | | |
| echo "β Deployment failed! Attempting rollback..." | |
| make rollback_hocuspocus.server_prod || echo "β οΈ Rollback failed or no previous version available" | |
| # ============================================================ | |
| # π DEPLOYMENT STRATEGY | |
| # ============================================================ | |
| # | |
| # FRONTEND (Next.js + PM2): | |
| # ------------------------- | |
| # β’ Uses PM2's built-in reload command for zero-downtime | |
| # β’ Cluster mode with rolling restart (one instance at a time) | |
| # β’ Health checks ensure each instance is ready before continuing | |
| # β’ Graceful shutdown via SIGTERM with 10s timeout | |
| # | |
| # BACKEND (Docker + Nginx): | |
| # ------------------------- | |
| # β’ Blue-Green deployment pattern | |
| # β’ Nginx reverse proxy for instant traffic switching | |
| # β’ New version (green) starts while old (blue) still serves traffic | |
| # β’ Health checks confirm new version is ready | |
| # β’ Traffic switches instantly via nginx config reload | |
| # β’ Old version gracefully shuts down after traffic switch | |
| # β’ 30s grace period for WebSocket connections to close | |
| # | |
| # ROLLBACK: | |
| # ------------------------- | |
| # β’ Automatic rollback on deployment failure | |
| # β’ Manual rollback: `make rollback_hocuspocus.server_prod` | |
| # β’ Instant switch back to previous version | |
| # | |
| # ============================================================ | |
| # π USAGE EXAMPLES | |
| # ============================================================ | |
| # | |
| # 1οΈβ£ Frontend only: | |
| # git commit -m "Feature: New UI component (build front)" | |
| # | |
| # 2οΈβ£ Backend only: | |
| # git commit -m "Fix: WebSocket connection (build back)" | |
| # | |
| # 3οΈβ£ Uptime Kuma only: | |
| # git commit -m "Update monitoring (build uptime-kuma)" | |
| # | |
| # 4οΈβ£ Frontend + Backend: | |
| # git commit -m "Full deploy (build front back)" | |
| # | |
| # 5οΈβ£ Everything at once: | |
| # git commit -m "Major release (build front back uptime-kuma)" | |
| # | |
| # Then push to main: | |
| # git push origin main | |
| # | |
| # ============================================================ |