主要变更: - 添加完整的项目结构和模块(admin、articles、comments、users、session、oauth2、email、moderation、analytics、jobs 等) - 实现系统初始化 API(/init/status 和 /init/run) - 重写部署流程:迁移到 package.json scripts,删除 Makefile - 优化部署脚本:deploy.sh、healthcheck.sh、backup.sh、restore.sh、verify-env.sh - 更新 README.md:简化文档,整合部署指南 - 优化 AGENTS.md:精简到约 150 行,包含完整的代码规范和命令速查 - 配置 Docker Compose 自动化部署(prisma migrate deploy + seed) - 生成 OAuth2 RSA 密钥对支持 - 添加环境变量验证和数据库备份恢复功能
247 lines
7.0 KiB
Bash
247 lines
7.0 KiB
Bash
#!/bin/bash
|
||
|
||
# ============================================
|
||
# LinkShare Blog - 增强健康检查脚本
|
||
# ============================================
|
||
# 用途: 全面检查系统状态,包括初始化状态
|
||
# 用法: ./scripts/healthcheck.sh [--admin-token TOKEN]
|
||
# 示例: ./scripts/healthcheck.sh
|
||
# ./scripts/healthcheck.sh --admin-token xxx
|
||
|
||
set -e
|
||
|
||
# API 地址
|
||
API_URL=${HEALTH_CHECK_URL:-http://localhost:3001}
|
||
ADMIN_TOKEN=${ADMIN_TOKEN:-}
|
||
|
||
# 颜色定义
|
||
GREEN='\033[0;32m'
|
||
RED='\033[0;31m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m'
|
||
|
||
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
|
||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||
log_step() { echo -e "${BLUE}[STEP]${NC} $1"; }
|
||
|
||
# 检查 API 健康
|
||
check_api() {
|
||
log_step "检查 API 健康状态..."
|
||
local response=$(curl -s -o /dev/null -w "%{http_code}" "$API_URL/health" 2>/dev/null)
|
||
|
||
if [ "$response" = "200" ]; then
|
||
log_info "✓ API 健康检查通过 (HTTP $response)"
|
||
return 0
|
||
else
|
||
log_error "✗ API 健康检查失败 (HTTP $response)"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# 检查数据库连接
|
||
check_database() {
|
||
log_step "检查数据库连接..."
|
||
local health_json=$(curl -s "$API_URL/health" 2>/dev/null || echo "")
|
||
|
||
if echo "$health_json" | grep -q '"database":"ok"'; then
|
||
log_info "✓ 数据库连接正常"
|
||
return 0
|
||
else
|
||
log_error "✗ 数据库连接异常"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# 检查 Redis 连接
|
||
check_redis() {
|
||
log_step "检查 Redis 连接..."
|
||
local health_json=$(curl -s "$API_URL/health" 2>/dev/null || echo "")
|
||
|
||
if echo "$health_json" | grep -q '"redis":"ok"'; then
|
||
log_info "✓ Redis 连接正常"
|
||
return 0
|
||
else
|
||
log_error "✗ Redis 连接异常"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# 检查初始化状态(需要管理员 token)
|
||
check_initialization() {
|
||
log_step "检查系统初始化状态..."
|
||
|
||
if [ -z "$ADMIN_TOKEN" ]; then
|
||
# 尝试从环境变量或 .env 文件获取管理员 token(简化版)
|
||
log_warn "未提供管理员 token,跳过初始化状态检查"
|
||
log_info "提示: 使用 --admin-token 参数或设置 ADMIN_TOKEN 环境变量"
|
||
return 0
|
||
fi
|
||
|
||
local response=$(curl -s -o /dev/null -w "%{http_code}" \
|
||
-H "Authorization: Bearer $ADMIN_TOKEN" \
|
||
"$API_URL/init/status" 2>/dev/null)
|
||
|
||
if [ "$response" = "200" ]; then
|
||
log_info "✓ 初始化状态检查成功"
|
||
# 可选:显示详细状态
|
||
# local status_json=$(curl -s -H "Authorization: Bearer $ADMIN_TOKEN" "$API_URL/init/status")
|
||
# echo "$status_json" | python3 -m json.tool 2>/dev/null || echo "$status_json"
|
||
return 0
|
||
else
|
||
log_error "✗ 初始化状态检查失败 (HTTP $response)"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# 检查关键 API 端点
|
||
check_endpoints() {
|
||
log_step "检查关键 API 端点..."
|
||
local all_ok=true
|
||
|
||
# 健康检查端点
|
||
if curl -sf "$API_URL/health" >/dev/null 2>/dev/null; then
|
||
log_info " ✓ GET /health"
|
||
else
|
||
log_error " ✗ GET /health 失败"
|
||
all_ok=false
|
||
fi
|
||
|
||
# 登录端点(不验证,只检查是否存在)
|
||
if curl -sf -X POST "$API_URL/login" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"emailOrUsername":"test","password":"test"}"' \
|
||
>/dev/null 2>&1; then
|
||
# 即使登录失败(401),端点也是可用的
|
||
log_info " ✓ POST /login (可用)"
|
||
else
|
||
log_error " ✗ POST /login 不可用"
|
||
all_ok=false
|
||
fi
|
||
|
||
# 初始化端点(需要管理员 token)
|
||
if [ -n "$ADMIN_TOKEN" ]; then
|
||
if curl -sf -H "Authorization: Bearer $ADMIN_TOKEN" "$API_URL/init/status" \
|
||
>/dev/null 2>&1; then
|
||
log_info " ✓ GET /init/status (管理员)"
|
||
else
|
||
log_warn " ⚠ GET /init/status 失败 (可能需要管理员权限)"
|
||
fi
|
||
fi
|
||
|
||
return $([ "$all_ok" = true ] && echo 0 || echo 1)
|
||
}
|
||
|
||
# 检查磁盘空间
|
||
check_disk() {
|
||
log_step "检查磁盘空间..."
|
||
local available=$(df -BG /app 2>/dev/null | tail -1 | awk '{print $4}' | sed 's/G//' || echo "0")
|
||
|
||
if [ "$available" -ge 5 ]; then
|
||
log_info "✓ 可用磁盘空间: ${available}GB"
|
||
return 0
|
||
else
|
||
log_warn "⚠ 可用磁盘空间: ${available}GB (建议至少 5GB)"
|
||
return 0 # 仅警告,不失败
|
||
fi
|
||
}
|
||
|
||
# 检查 Docker 容器状态
|
||
check_containers() {
|
||
log_step "检查 Docker 容器状态..."
|
||
local all_running=true
|
||
|
||
# 检查 API 容器
|
||
if docker ps --format '{{.Names}}' | grep -q 'blog-api'; then
|
||
log_info " ✓ API 容器运行中"
|
||
else
|
||
log_error " ✗ API 容器未运行"
|
||
all_running=false
|
||
fi
|
||
|
||
# 检查数据库容器
|
||
if docker ps --format '{{.Names}}' | grep -q 'blog-postgres'; then
|
||
log_info " ✓ PostgreSQL 容器运行中"
|
||
else
|
||
log_error " ✗ PostgreSQL 容器未运行"
|
||
all_running=false
|
||
fi
|
||
|
||
# 检查 Redis 容器
|
||
if docker ps --format '{{.Names}}' | grep -q 'blog-redis'; then
|
||
log_info " ✓ Redis 容器运行中"
|
||
else
|
||
log_error " ✗ Redis 容器未运行"
|
||
all_running=false
|
||
fi
|
||
|
||
return $([ "$all_running" = true ] && echo 0 || echo 1)
|
||
}
|
||
|
||
# 主检查流程
|
||
main() {
|
||
echo "=========================================="
|
||
echo "LinkShare Blog 系统健康检查"
|
||
echo "检查时间: $(date '+%Y-%m-%d %H:%M:%S')"
|
||
echo "API URL: $API_URL"
|
||
echo "=========================================="
|
||
echo ""
|
||
|
||
local all_passed=true
|
||
|
||
# 1. 容器状态检查
|
||
if command -v docker &>/dev/null; then
|
||
check_containers || all_passed=false
|
||
echo ""
|
||
fi
|
||
|
||
# 2. API 健康检查
|
||
check_api || all_passed=false
|
||
echo ""
|
||
|
||
# 3. 数据库检查
|
||
check_database || all_passed=false
|
||
echo ""
|
||
|
||
# 4. Redis 检查
|
||
check_redis || all_passed=false
|
||
echo ""
|
||
|
||
# 5. 初始化状态检查
|
||
check_initialization || all_passed=false
|
||
echo ""
|
||
|
||
# 6. 关键端点检查
|
||
check_endpoints || all_passed=false
|
||
echo ""
|
||
|
||
# 7. 磁盘空间检查
|
||
check_disk
|
||
echo ""
|
||
|
||
# 总结
|
||
echo "=========================================="
|
||
if [ "$all_passed" = true ]; then
|
||
log_info "所有关键检查通过!系统运行正常。"
|
||
echo ""
|
||
echo "下一步:"
|
||
echo " - 访问 API: $API_URL"
|
||
echo " - Swagger 文档: $API_URL/api-docs (开发环境)"
|
||
echo " - 初始化状态: $API_URL/init/status (需要管理员 Token)"
|
||
exit 0
|
||
else
|
||
log_error "部分检查失败,请排查上述问题。"
|
||
echo ""
|
||
echo "故障排查:"
|
||
echo " - 查看日志: docker-compose logs -f api"
|
||
echo " - 重启服务: make restart"
|
||
echo " - 重新部署: make deploy"
|
||
echo " - 查看文档: DEPLOYMENT.md"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# 运行主函数
|
||
main
|