#!/bin/bash # Health check script for blue-green deployment # Verifies container health and HTTP endpoints # # Usage: ./health-check.sh [timeout_seconds] # stack: blue or green # timeout_seconds: max wait time (default: 60) # # Exit codes: # 0 - All health checks passed # 1 - Health check failed set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" STACK="${1:-}" TIMEOUT="${2:-60}" if [[ -z "$STACK" ]] || [[ ! "$STACK" =~ ^(blue|green)$ ]]; then echo "Usage: $0 [timeout_seconds]" exit 1 fi FRONTEND_CONTAINER="mvp-frontend-$STACK" BACKEND_CONTAINER="mvp-backend-$STACK" echo "========================================" echo "Health Check - $STACK Stack" echo "Timeout: ${TIMEOUT}s" echo "========================================" # Function to check Docker container health check_container_health() { local container="$1" local status status=$(docker inspect --format='{{.State.Health.Status}}' "$container" 2>/dev/null || echo "not found") case "$status" in "healthy") return 0 ;; "starting") return 2 # Still starting ;; "unhealthy"|"not found"|"") return 1 ;; *) return 1 ;; esac } # Function to check HTTP endpoint check_http_endpoint() { local container="$1" local port="$2" local path="$3" if docker exec "$container" curl -sf "http://localhost:${port}${path}" > /dev/null 2>&1; then return 0 else return 1 fi } # Function to check database connectivity via backend check_database_connectivity() { local container="$1" # The /health endpoint should verify database connectivity if docker exec "$container" curl -sf "http://localhost:3001/health" 2>/dev/null | grep -q '"database"'; then return 0 else return 1 fi } # Wait for containers to be healthy wait_for_health() { local container="$1" local elapsed=0 while [[ $elapsed -lt $TIMEOUT ]]; do check_container_health "$container" local status=$? if [[ $status -eq 0 ]]; then return 0 elif [[ $status -eq 1 ]]; then echo " ERROR: Container $container is unhealthy" docker logs "$container" --tail 20 2>/dev/null || true return 1 fi # Still starting, wait sleep 2 elapsed=$((elapsed + 2)) echo " Waiting for $container... (${elapsed}s/${TIMEOUT}s)" done echo " ERROR: Timeout waiting for $container" return 1 } # Main health check sequence echo "" echo "Step 1/4: Checking container status..." echo "----------------------------------------" for container in "$FRONTEND_CONTAINER" "$BACKEND_CONTAINER"; do running=$(docker inspect --format='{{.State.Running}}' "$container" 2>/dev/null || echo "false") if [[ "$running" != "true" ]]; then echo " ERROR: Container $container is not running" docker ps -a --filter "name=$container" --format "table {{.Names}}\t{{.Status}}" exit 1 fi echo " OK: $container is running" done echo "" echo "Step 2/4: Waiting for Docker health checks..." echo "----------------------------------------" for container in "$FRONTEND_CONTAINER" "$BACKEND_CONTAINER"; do echo " Checking $container..." if ! wait_for_health "$container"; then echo " FAILED: $container health check" exit 1 fi echo " OK: $container is healthy" done echo "" echo "Step 3/4: Verifying HTTP endpoints..." echo "----------------------------------------" # Check frontend echo " Checking frontend HTTP..." if ! check_http_endpoint "$FRONTEND_CONTAINER" 3000 "/"; then echo " FAILED: Frontend HTTP check" exit 1 fi echo " OK: Frontend responds on port 3000" # Check backend health endpoint echo " Checking backend HTTP..." if ! check_http_endpoint "$BACKEND_CONTAINER" 3001 "/health"; then echo " FAILED: Backend HTTP check" exit 1 fi echo " OK: Backend responds on port 3001" echo "" echo "Step 4/4: Verifying database connectivity..." echo "----------------------------------------" if ! check_database_connectivity "$BACKEND_CONTAINER"; then echo " WARNING: Could not verify database connectivity" echo " (Backend may not expose database status in /health)" else echo " OK: Database connectivity verified" fi echo "" echo "========================================" echo "Health Check PASSED - $STACK Stack" echo "========================================" # Update state file STATE_FILE="$PROJECT_ROOT/config/deployment/state.json" if [[ -f "$STATE_FILE" ]]; then # Update stack health status using jq if available if command -v jq &> /dev/null; then TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ") jq --arg stack "$STACK" --arg ts "$TIMESTAMP" \ '.[$stack].healthy = true | .[$stack].last_health_check = $ts' \ "$STATE_FILE" > "${STATE_FILE}.tmp" && mv "${STATE_FILE}.tmp" "$STATE_FILE" fi fi exit 0