← back to Handbag Auth Nextjs
scripts/devops/health-check.sh
174 lines
#!/bin/bash
# Comprehensive Health Check Script for Auction Viewer
# Runs every 5 minutes via cron to monitor application health
set -euo pipefail
# Configuration
SERVICE_NAME="auction-viewer"
SERVICE_URL="http://45.61.58.125:7500"
HEALTH_ENDPOINT="${SERVICE_URL}/health"
READY_ENDPOINT="${SERVICE_URL}/ready"
LOG_FILE="/root/Projects/handbag-auth-nextjs/logs/health-check.log"
METRICS_FILE="/root/Projects/handbag-auth-nextjs/data/auction-history/metrics.log"
ALERT_EMAIL="" # Set email for alerts
MAX_RESPONSE_TIME=5000 # milliseconds
MAX_ERROR_RATE=10 # percentage
# Create log directory if needed
mkdir -p "$(dirname "${LOG_FILE}")"
# Logging function
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}"
}
# Metrics logging
log_metrics() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "${METRICS_FILE}"
}
# Alert function (can be extended to send emails/Slack notifications)
send_alert() {
local message=$1
log "ALERT: ${message}"
# Uncomment to enable Slack notifications
# curl -X POST -H 'Content-type: application/json' \
# --data "{\"text\":\"AUCTION VIEWER ALERT: ${message}\"}" \
# YOUR_SLACK_WEBHOOK_URL
}
# Check if service is running in PM2
check_pm2_status() {
if pm2 show "${SERVICE_NAME}" | grep -q "online"; then
return 0
else
return 1
fi
}
# Check HTTP endpoint with timeout
check_endpoint() {
local endpoint=$1
local timeout=5
START_TIME=$(date +%s%3N)
RESPONSE=$(curl -s -w "\n%{http_code}\n%{time_total}" --max-time ${timeout} "${endpoint}" 2>/dev/null || echo "000")
END_TIME=$(date +%s%3N)
HTTP_CODE=$(echo "${RESPONSE}" | tail -n 2 | head -n 1)
RESPONSE_TIME=$((END_TIME - START_TIME))
echo "${HTTP_CODE}:${RESPONSE_TIME}"
}
# Main health check
perform_health_check() {
local status="HEALTHY"
local issues=()
# Check 1: PM2 Process Status
if ! check_pm2_status; then
status="CRITICAL"
issues+=("PM2 process not running")
log "CRITICAL: ${SERVICE_NAME} not running in PM2"
# Auto-restart if not running
log "Attempting to restart ${SERVICE_NAME}..."
cd /root/Projects/handbag-auth-nextjs/auction-viewer
pm2 start server.js --name "${SERVICE_NAME}" 2>&1 | tee -a "${LOG_FILE}"
sleep 5
if check_pm2_status; then
log "Service restarted successfully"
send_alert "Service was down and has been auto-restarted"
else
log "CRITICAL: Failed to restart service"
send_alert "Service down and auto-restart failed - manual intervention required"
return 1
fi
fi
# Check 2: Health Endpoint
HEALTH_CHECK=$(check_endpoint "${HEALTH_ENDPOINT}")
HEALTH_CODE=$(echo "${HEALTH_CHECK}" | cut -d: -f1)
HEALTH_TIME=$(echo "${HEALTH_CHECK}" | cut -d: -f2)
if [ "${HEALTH_CODE}" != "200" ]; then
status="UNHEALTHY"
issues+=("Health endpoint returned ${HEALTH_CODE}")
log "WARNING: Health endpoint returned ${HEALTH_CODE}"
fi
if [ "${HEALTH_TIME}" -gt "${MAX_RESPONSE_TIME}" ]; then
status="DEGRADED"
issues+=("Slow response time: ${HEALTH_TIME}ms")
log "WARNING: Slow response time: ${HEALTH_TIME}ms"
fi
# Check 3: Readiness Endpoint
READY_CHECK=$(check_endpoint "${READY_ENDPOINT}")
READY_CODE=$(echo "${READY_CHECK}" | cut -d: -f1)
if [ "${READY_CODE}" != "200" ]; then
status="NOT_READY"
issues+=("Readiness check failed")
log "WARNING: Readiness check failed"
fi
# Check 4: Database Accessibility
DB_PATH="/root/Projects/handbag-auth-nextjs/data/auction-history/auctions.db"
if [ ! -f "${DB_PATH}" ]; then
status="CRITICAL"
issues+=("Database file not found")
log "CRITICAL: Database file not found"
send_alert "Database file missing at ${DB_PATH}"
else
# Test database integrity
if ! sqlite3 "${DB_PATH}" "SELECT COUNT(*) FROM auctions;" > /dev/null 2>&1; then
status="CRITICAL"
issues+=("Database query failed")
log "CRITICAL: Database query failed"
send_alert "Database query failed - possible corruption"
fi
fi
# Check 5: Disk Space
DISK_USAGE=$(df -h /root/Projects/handbag-auth-nextjs | tail -1 | awk '{print $5}' | sed 's/%//')
if [ "${DISK_USAGE}" -gt 90 ]; then
status="WARNING"
issues+=("Disk usage at ${DISK_USAGE}%")
log "WARNING: Disk usage at ${DISK_USAGE}%"
send_alert "Disk usage critical: ${DISK_USAGE}%"
fi
# Check 6: Memory Usage
MEM_USAGE=$(pm2 show "${SERVICE_NAME}" | grep memory | awk '{print $4}')
log "Memory usage: ${MEM_USAGE}"
# Log metrics
log_metrics "status=${status},health_code=${HEALTH_CODE},response_time=${HEALTH_TIME}ms,disk=${DISK_USAGE}%,memory=${MEM_USAGE}"
# Report status
if [ "${status}" == "HEALTHY" ]; then
log "Health check PASSED - All systems operational (response: ${HEALTH_TIME}ms)"
else
log "Health check FAILED - Status: ${status}"
for issue in "${issues[@]}"; do
log " - ${issue}"
done
fi
return 0
}
# Execute health check
perform_health_check
# Cleanup old logs (keep last 1000 lines)
if [ -f "${LOG_FILE}" ]; then
tail -n 1000 "${LOG_FILE}" > "${LOG_FILE}.tmp"
mv "${LOG_FILE}.tmp" "${LOG_FILE}"
fi