Skip to content

build: back

build: back #348

# 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
#
# ============================================================