barsa 22c9428c77 Enhance real-time event handling and configuration in BFF application
- Updated environment validation to enable Salesforce events by default, improving real-time cache invalidation.
- Modified `CatalogCdcSubscriber` to conditionally subscribe to CDC channels based on the new configuration, enhancing flexibility for high-volume scenarios.
- Improved message serialization in `RealtimeService` to ensure valid JSON for browser EventSource.
- Adjusted cache control headers in `CatalogController` to prevent browser caching, ensuring real-time data accuracy.
- Enhanced `RealtimeController` with connection limiting and improved logging for better monitoring of real-time streams.
- Updated health check endpoint in production management script for consistency.
2025-12-15 11:55:55 +09:00

210 lines
7.4 KiB
Bash
Executable File

#!/bin/bash
# 🚀 Production Environment Manager
# Manages production Docker deployment with organized structure
set -e
# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
COMPOSE_FILE="${COMPOSE_FILE:-$PROJECT_ROOT/docker/prod/docker-compose.yml}"
ENV_FILE="$PROJECT_ROOT/.env"
PROJECT_NAME="portal-prod"
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
RED='\033[0;31m'
NC='\033[0m'
log() { echo -e "${GREEN}[PROD] $1${NC}"; }
warn() { echo -e "${YELLOW}[PROD] $1${NC}"; }
info() { echo -e "${BLUE}[PROD] $1${NC}"; }
error() { echo -e "${RED}[PROD] ERROR: $1${NC}"; exit 1; }
# Change to project root
cd "$PROJECT_ROOT"
# Check environment file
check_env() {
if [ ! -f "$ENV_FILE" ]; then
log "Creating environment file from template..."
cp .env.example .env
error "Environment file created at $ENV_FILE. Please edit it with your production values before deploying."
fi
# Check for required variables
required_vars=("DATABASE_URL" "REDIS_URL" "JWT_SECRET" "POSTGRES_PASSWORD" "CORS_ORIGIN" "NEXT_PUBLIC_API_BASE" "BFF_PORT")
for var in "${required_vars[@]}"; do
if ! grep -q "^$var=" "$ENV_FILE" || grep -q "^$var=.*CHANGE_THIS" "$ENV_FILE"; then
error "Required environment variable $var is not properly set in $ENV_FILE"
fi
done
}
issue_cert() {
local domain="$1"
local email="$2"
if [ -z "$domain" ] || [ -z "$email" ]; then
error "Usage: $0 issue-cert <domain> <email>"
fi
log "🔐 Issuing certificate for $domain ..."
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" run --rm -p 80:80 \
-e CERTBOT_DOMAIN="$domain" -e CERTBOT_EMAIL="$email" certbot \
certonly --webroot -w /var/www/certbot -d "$domain" --agree-tos --no-eff-email
log "✅ Certificate issuance process completed"
}
# Build production images
build_images() {
log "🔨 Building production images..."
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" build --no-cache
log "✅ Images built successfully"
}
# Deploy production environment
deploy() {
log "🚀 Deploying production environment..."
check_env
build_images
# Start database and cache first
log "🗄️ Starting database and cache..."
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" up -d database cache
# Wait for database
log "⏳ Waiting for database..."
timeout=60
while [ $timeout -gt 0 ]; do
if docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" exec -T database pg_isready -U portal -d portal_prod 2>/dev/null; then
log "✅ Database is ready"
break
fi
sleep 2
timeout=$((timeout - 2))
done
if [ $timeout -eq 0 ]; then
error "Database failed to start within 60 seconds"
fi
# Run migrations
log "🔄 Running database migrations..."
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" run --rm backend pnpm db:migrate || warn "Migration may have failed"
# Start application services (apps only; Plesk handles proxy)
log "🚀 Starting application services..."
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" up -d frontend backend
# Health checks
log "🏥 Performing health checks..."
sleep 15
if docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" ps | grep -q "unhealthy"; then
warn "Some services may not be healthy - check logs"
fi
log "✅ Production deployment completed!"
log "🔗 Frontend: http://localhost:3000"
log "🔗 Backend API: http://localhost:4000"
}
# Stop production services
stop() {
log "⏹️ Stopping production services..."
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" down
log "✅ Services stopped"
}
# Update deployment
update() {
log "🔄 Updating production deployment..."
check_env
build_images
# Zero-downtime update
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" up -d --force-recreate --no-deps backend frontend
log "✅ Production update completed"
}
# Show status with health checks
status() {
log "📊 Production Services Status:"
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" ps
log "🏥 Health Status:"
# If proxy service exists (non-Plesk mode), check it; otherwise, check frontend directly
if docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" ps proxy >/dev/null 2>&1; then
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" exec proxy wget --spider -q http://localhost/healthz && echo "✅ Proxy/Frontend healthy" || echo "❌ Proxy/Frontend unhealthy"
else
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" exec frontend wget --spider -q http://localhost:3000/_health && echo "✅ Frontend healthy" || echo "❌ Frontend unhealthy"
fi
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" exec backend wget --spider -q http://localhost:4000/health && echo "✅ Backend healthy" || echo "❌ Backend unhealthy"
}
# Show logs
logs() {
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" logs -f "${@:2}"
}
# Backup database
backup() {
log "💾 Creating database backup..."
backup_file="backup_$(date +%Y%m%d_%H%M%S).sql"
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" exec -T database pg_dump -U portal portal_prod > "$backup_file"
log "✅ Database backup created: $backup_file"
}
# Clean up
cleanup() {
log "🧹 Cleaning up old containers and images..."
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" down --remove-orphans
docker system prune -f
docker image prune -f
log "✅ Cleanup completed"
}
# Main function
case "${1:-help}" in
"deploy") deploy ;;
"start")
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" up -d
log "✅ Production services started"
;;
"stop") stop ;;
"restart")
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" restart
log "✅ Services restarted"
;;
"update") update ;;
"build") build_images ;;
"issue-cert") issue_cert "$2" "$3" ;;
"status") status ;;
"logs") logs "$@" ;;
"backup") backup ;;
"cleanup") cleanup ;;
"help"|*)
echo "🚀 Production Environment Manager"
echo ""
echo "Usage: $0 {command}"
echo ""
echo "Commands:"
echo " deploy - Full deployment (build + start + migrate)"
echo " start - Start all production services"
echo " stop - Stop all production services"
echo " restart - Restart all services"
echo " update - Update deployment with new images"
echo " build - Build production images"
echo " status - Show service status and health"
echo " logs - Show service logs"
echo " backup - Create database backup"
echo " cleanup - Clean up old containers and images"
echo " help - Show this help"
exit 0
;;
esac