feat(presence-service): 添加完整的部署脚本
- 添加 deploy.sh 主部署脚本 (build/start/stop/logs/migrate/test) - 添加 scripts/quick-test.sh API 快速测试脚本 - 添加 scripts/rebuild-kafka.sh Kafka 重建脚本 - 更新 scripts/README.md 文档 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
603c1c6c90
commit
f132b86899
|
|
@ -0,0 +1,204 @@
|
|||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# Presence Service - Individual Deployment Script
|
||||
# =============================================================================
|
||||
|
||||
set -e
|
||||
|
||||
SERVICE_NAME="presence-service"
|
||||
CONTAINER_NAME="presence-service"
|
||||
IMAGE_NAME="presence-service"
|
||||
PORT=3001
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||
log_success() { echo -e "${GREEN}[OK]${NC} $1"; }
|
||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
|
||||
# Get script directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Load environment
|
||||
if [ -f "$SCRIPT_DIR/.env.production" ]; then
|
||||
export $(cat "$SCRIPT_DIR/.env.production" | grep -v '^#' | xargs)
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
build)
|
||||
log_info "Building $SERVICE_NAME..."
|
||||
docker build -t "$IMAGE_NAME" "$SCRIPT_DIR"
|
||||
log_success "$SERVICE_NAME built successfully"
|
||||
;;
|
||||
|
||||
build-no-cache)
|
||||
log_info "Building $SERVICE_NAME (no cache)..."
|
||||
docker build --no-cache -t "$IMAGE_NAME" "$SCRIPT_DIR"
|
||||
log_success "$SERVICE_NAME built successfully"
|
||||
;;
|
||||
|
||||
start)
|
||||
log_info "Starting $SERVICE_NAME..."
|
||||
cd "$SCRIPT_DIR"
|
||||
docker compose up -d
|
||||
log_success "$SERVICE_NAME started"
|
||||
;;
|
||||
|
||||
start-deps)
|
||||
log_info "Starting dependencies only..."
|
||||
cd "$SCRIPT_DIR"
|
||||
docker compose -f docker-compose.dev.yml up -d
|
||||
log_success "Dependencies started"
|
||||
;;
|
||||
|
||||
stop)
|
||||
log_info "Stopping $SERVICE_NAME..."
|
||||
cd "$SCRIPT_DIR"
|
||||
docker compose down
|
||||
log_success "$SERVICE_NAME stopped"
|
||||
;;
|
||||
|
||||
stop-deps)
|
||||
log_info "Stopping dependencies..."
|
||||
cd "$SCRIPT_DIR"
|
||||
docker compose -f docker-compose.dev.yml down
|
||||
log_success "Dependencies stopped"
|
||||
;;
|
||||
|
||||
restart)
|
||||
$0 stop
|
||||
$0 start
|
||||
;;
|
||||
|
||||
logs)
|
||||
docker logs -f "$CONTAINER_NAME"
|
||||
;;
|
||||
|
||||
logs-tail)
|
||||
docker logs --tail 100 "$CONTAINER_NAME"
|
||||
;;
|
||||
|
||||
status)
|
||||
if docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
||||
log_success "$SERVICE_NAME is running"
|
||||
docker ps --filter "name=$CONTAINER_NAME" --format "table {{.Status}}\t{{.Ports}}"
|
||||
else
|
||||
log_warn "$SERVICE_NAME is not running"
|
||||
fi
|
||||
;;
|
||||
|
||||
health)
|
||||
log_info "Checking health of $SERVICE_NAME..."
|
||||
if curl -sf "http://localhost:$PORT/api/v1/health" > /dev/null 2>&1; then
|
||||
HEALTH=$(curl -s "http://localhost:$PORT/api/v1/health")
|
||||
log_success "$SERVICE_NAME is healthy"
|
||||
echo "$HEALTH"
|
||||
else
|
||||
log_error "$SERVICE_NAME health check failed"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
migrate)
|
||||
log_info "Running migrations for $SERVICE_NAME..."
|
||||
docker exec "$CONTAINER_NAME" npx prisma migrate deploy
|
||||
log_success "Migrations completed"
|
||||
;;
|
||||
|
||||
migrate-dev)
|
||||
log_info "Running dev migrations for $SERVICE_NAME..."
|
||||
docker exec "$CONTAINER_NAME" npx prisma migrate dev
|
||||
;;
|
||||
|
||||
db-push)
|
||||
log_info "Pushing schema to database..."
|
||||
docker exec "$CONTAINER_NAME" npx prisma db push
|
||||
log_success "Schema pushed"
|
||||
;;
|
||||
|
||||
prisma-studio)
|
||||
log_info "Starting Prisma Studio..."
|
||||
docker exec -it "$CONTAINER_NAME" npx prisma studio
|
||||
;;
|
||||
|
||||
shell)
|
||||
log_info "Opening shell in $SERVICE_NAME container..."
|
||||
docker exec -it "$CONTAINER_NAME" sh
|
||||
;;
|
||||
|
||||
test)
|
||||
log_info "Running tests for $SERVICE_NAME..."
|
||||
cd "$SCRIPT_DIR"
|
||||
npm test
|
||||
;;
|
||||
|
||||
test-unit)
|
||||
log_info "Running unit tests..."
|
||||
cd "$SCRIPT_DIR"
|
||||
npm run test:unit
|
||||
;;
|
||||
|
||||
test-integration)
|
||||
log_info "Running integration tests..."
|
||||
cd "$SCRIPT_DIR"
|
||||
npm run test:integration
|
||||
;;
|
||||
|
||||
test-e2e)
|
||||
log_info "Running E2E tests..."
|
||||
cd "$SCRIPT_DIR"
|
||||
npm run test:e2e
|
||||
;;
|
||||
|
||||
clean)
|
||||
log_info "Cleaning up..."
|
||||
cd "$SCRIPT_DIR"
|
||||
docker compose down -v
|
||||
docker rmi "$IMAGE_NAME" 2>/dev/null || true
|
||||
log_success "Cleanup completed"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Usage: $0 {command}"
|
||||
echo ""
|
||||
echo "Build Commands:"
|
||||
echo " build - Build Docker image"
|
||||
echo " build-no-cache - Build Docker image without cache"
|
||||
echo ""
|
||||
echo "Service Commands:"
|
||||
echo " start - Start the full stack (service + dependencies)"
|
||||
echo " start-deps - Start dependencies only (for local development)"
|
||||
echo " stop - Stop all containers"
|
||||
echo " stop-deps - Stop dependencies only"
|
||||
echo " restart - Restart the service"
|
||||
echo ""
|
||||
echo "Monitoring Commands:"
|
||||
echo " logs - Follow logs"
|
||||
echo " logs-tail - Show last 100 log lines"
|
||||
echo " status - Show service status"
|
||||
echo " health - Check service health"
|
||||
echo ""
|
||||
echo "Database Commands:"
|
||||
echo " migrate - Run database migrations (production)"
|
||||
echo " migrate-dev - Run dev migrations"
|
||||
echo " db-push - Push Prisma schema to database"
|
||||
echo " prisma-studio - Open Prisma Studio"
|
||||
echo ""
|
||||
echo "Development Commands:"
|
||||
echo " shell - Open shell in container"
|
||||
echo " test - Run all tests"
|
||||
echo " test-unit - Run unit tests only"
|
||||
echo " test-integration - Run integration tests only"
|
||||
echo " test-e2e - Run E2E tests only"
|
||||
echo ""
|
||||
echo "Maintenance Commands:"
|
||||
echo " clean - Remove containers and images"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
|
@ -7,6 +7,14 @@
|
|||
| `start-all.sh` | 一键启动所有服务 | 开发环境初始化 |
|
||||
| `stop-service.sh` | 停止 Presence Service | 重启服务、关闭开发环境 |
|
||||
| `health-check.sh` | 检查所有服务健康状态 | 部署验证、故障排查 |
|
||||
| `quick-test.sh` | 快速 API 功能测试 | 验证核心功能 |
|
||||
| `rebuild-kafka.sh` | 重建 Kafka 容器 | Kafka 配置变更后 |
|
||||
|
||||
另外,项目根目录还有:
|
||||
|
||||
| 脚本 | 用途 | 使用场景 |
|
||||
|-----|------|---------|
|
||||
| `deploy.sh` | 完整部署管理脚本 | 生产部署、容器管理 |
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -52,7 +60,15 @@ Failed: 0
|
|||
✓ All services are healthy!
|
||||
```
|
||||
|
||||
### 3️⃣ 停止服务
|
||||
### 3️⃣ 快速测试
|
||||
|
||||
```bash
|
||||
./scripts/quick-test.sh
|
||||
```
|
||||
|
||||
验证核心 API 功能是否正常工作。
|
||||
|
||||
### 4️⃣ 停止服务
|
||||
|
||||
```bash
|
||||
./scripts/stop-service.sh
|
||||
|
|
@ -60,6 +76,46 @@ Failed: 0
|
|||
|
||||
---
|
||||
|
||||
## deploy.sh 使用指南
|
||||
|
||||
`deploy.sh` 是一个功能完整的部署管理脚本,支持以下命令:
|
||||
|
||||
```bash
|
||||
# 构建 Docker 镜像
|
||||
./deploy.sh build
|
||||
./deploy.sh build-no-cache
|
||||
|
||||
# 启动/停止服务
|
||||
./deploy.sh start # 启动完整环境
|
||||
./deploy.sh start-deps # 只启动依赖(开发模式)
|
||||
./deploy.sh stop # 停止所有
|
||||
./deploy.sh restart # 重启
|
||||
|
||||
# 监控
|
||||
./deploy.sh logs # 实时日志
|
||||
./deploy.sh logs-tail # 最近 100 行日志
|
||||
./deploy.sh status # 服务状态
|
||||
./deploy.sh health # 健康检查
|
||||
|
||||
# 数据库
|
||||
./deploy.sh migrate # 生产环境迁移
|
||||
./deploy.sh migrate-dev # 开发环境迁移
|
||||
./deploy.sh db-push # 推送 Schema
|
||||
./deploy.sh prisma-studio # 打开 Prisma Studio
|
||||
|
||||
# 开发
|
||||
./deploy.sh shell # 进入容器 Shell
|
||||
./deploy.sh test # 运行所有测试
|
||||
./deploy.sh test-unit # 单元测试
|
||||
./deploy.sh test-integration # 集成测试
|
||||
./deploy.sh test-e2e # E2E 测试
|
||||
|
||||
# 清理
|
||||
./deploy.sh clean # 删除容器和镜像
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 服务端口
|
||||
|
||||
| 服务 | 开发端口 | 说明 |
|
||||
|
|
|
|||
|
|
@ -0,0 +1,140 @@
|
|||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# Presence Service - Quick Test Script
|
||||
# =============================================================================
|
||||
# Quickly verify core API functionality in local environment.
|
||||
# =============================================================================
|
||||
|
||||
set -e
|
||||
|
||||
echo "🚀 Starting quick API tests..."
|
||||
echo ""
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
BASE_URL="http://localhost:3001/api/v1"
|
||||
|
||||
# Test counters
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
# Test function
|
||||
test_api() {
|
||||
local test_name=$1
|
||||
local method=$2
|
||||
local endpoint=$3
|
||||
local data=$4
|
||||
local expected_status=$5
|
||||
local token=$6
|
||||
|
||||
echo -n "Testing: $test_name ... "
|
||||
|
||||
if [ -n "$token" ]; then
|
||||
response=$(curl -s -w "\n%{http_code}" -X $method "$BASE_URL$endpoint" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $token" \
|
||||
-d "$data" 2>/dev/null)
|
||||
elif [ -n "$data" ]; then
|
||||
response=$(curl -s -w "\n%{http_code}" -X $method "$BASE_URL$endpoint" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$data" 2>/dev/null)
|
||||
else
|
||||
response=$(curl -s -w "\n%{http_code}" -X $method "$BASE_URL$endpoint" \
|
||||
-H "Content-Type: application/json" 2>/dev/null)
|
||||
fi
|
||||
|
||||
status=$(echo "$response" | tail -n1)
|
||||
body=$(echo "$response" | head -n-1)
|
||||
|
||||
if [ "$status" -eq "$expected_status" ]; then
|
||||
echo -e "${GREEN}✓ PASS${NC}"
|
||||
PASS=$((PASS + 1))
|
||||
if [ -n "$body" ]; then
|
||||
echo "$body" | head -c 200
|
||||
echo ""
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}✗ FAIL${NC} (Expected: $expected_status, Got: $status)"
|
||||
FAIL=$((FAIL + 1))
|
||||
echo "$body"
|
||||
fi
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Generate test data
|
||||
INSTALL_ID="test-install-$(date +%s)"
|
||||
USER_ID="test-user-$(date +%s)"
|
||||
|
||||
# =============================================================================
|
||||
# 1. Health Check
|
||||
# =============================================================================
|
||||
echo -e "${YELLOW}=== 1. Health Check ===${NC}"
|
||||
test_api "Health endpoint" "GET" "/health" "" 200 ""
|
||||
|
||||
# =============================================================================
|
||||
# 2. Presence API (requires auth - should return 401)
|
||||
# =============================================================================
|
||||
echo -e "${YELLOW}=== 2. Presence API (Auth Required) ===${NC}"
|
||||
test_api "Heartbeat without auth" "POST" "/presence/heartbeat" \
|
||||
"{\"installId\": \"$INSTALL_ID\"}" \
|
||||
401 ""
|
||||
|
||||
test_api "Online count without auth" "GET" "/presence/online-count" "" 401 ""
|
||||
|
||||
test_api "Online history without auth" "GET" "/presence/online-history?startDate=2024-01-01&endDate=2024-01-31" "" 401 ""
|
||||
|
||||
# =============================================================================
|
||||
# 3. Analytics API (requires auth - should return 401)
|
||||
# =============================================================================
|
||||
echo -e "${YELLOW}=== 3. Analytics API (Auth Required) ===${NC}"
|
||||
test_api "Track event without auth" "POST" "/analytics/events" \
|
||||
"{\"installId\": \"$INSTALL_ID\", \"eventName\": \"app_open\", \"eventData\": {}}" \
|
||||
401 ""
|
||||
|
||||
test_api "DAU stats without auth" "GET" "/analytics/dau?date=2024-01-01" "" 401 ""
|
||||
|
||||
# =============================================================================
|
||||
# 4. API with Mock Token (will fail auth validation but test routing)
|
||||
# =============================================================================
|
||||
echo -e "${YELLOW}=== 4. API Routing Test (Invalid Token) ===${NC}"
|
||||
FAKE_TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlRlc3QiLCJpYXQiOjE1MTYyMzkwMjJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
|
||||
|
||||
test_api "Heartbeat with invalid token" "POST" "/presence/heartbeat" \
|
||||
"{\"installId\": \"$INSTALL_ID\"}" \
|
||||
401 "$FAKE_TOKEN"
|
||||
|
||||
# =============================================================================
|
||||
# 5. Error Handling
|
||||
# =============================================================================
|
||||
echo -e "${YELLOW}=== 5. Error Handling ===${NC}"
|
||||
test_api "Non-existent endpoint" "GET" "/non-existent" "" 404 ""
|
||||
|
||||
test_api "Invalid JSON body" "POST" "/analytics/events" \
|
||||
"invalid-json" \
|
||||
400 ""
|
||||
|
||||
# =============================================================================
|
||||
# Summary
|
||||
# =============================================================================
|
||||
echo ""
|
||||
echo -e "${YELLOW}======================================${NC}"
|
||||
echo -e "${YELLOW}Test Summary${NC}"
|
||||
echo -e "${GREEN}Passed: $PASS${NC}"
|
||||
echo -e "${RED}Failed: $FAIL${NC}"
|
||||
echo -e "${YELLOW}======================================${NC}"
|
||||
|
||||
if [ $FAIL -eq 0 ]; then
|
||||
echo -e "${GREEN}✓ All tests passed!${NC}"
|
||||
echo ""
|
||||
echo -e "${BLUE}Note:${NC} Most endpoints require authentication."
|
||||
echo "For full testing, use: npm run test:e2e"
|
||||
exit 0
|
||||
else
|
||||
echo -e "${RED}✗ Some tests failed!${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# Presence Service - Rebuild Kafka Script
|
||||
# =============================================================================
|
||||
# Rebuilds Kafka container to apply new configuration.
|
||||
# =============================================================================
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
echo -e "${YELLOW}🔄 Rebuilding Kafka containers...${NC}"
|
||||
echo ""
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# 1. Stop Presence Service (if running)
|
||||
echo -e "${BLUE}Step 1: Stop Presence Service${NC}"
|
||||
PID=$(lsof -ti :3001 2>/dev/null)
|
||||
if [ ! -z "$PID" ]; then
|
||||
echo "Stopping Presence Service (PID: $PID)..."
|
||||
kill $PID 2>/dev/null || true
|
||||
sleep 2
|
||||
echo -e "${GREEN}✓ Presence Service stopped${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ Presence Service is not running${NC}"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 2. Stop and remove Kafka and Zookeeper containers
|
||||
echo -e "${BLUE}Step 2: Stop and remove old containers${NC}"
|
||||
docker compose -f docker-compose.dev.yml stop kafka zookeeper 2>/dev/null || true
|
||||
docker compose -f docker-compose.dev.yml rm -f kafka zookeeper 2>/dev/null || true
|
||||
echo -e "${GREEN}✓ Old containers removed${NC}"
|
||||
echo ""
|
||||
|
||||
# 3. Recreate containers
|
||||
echo -e "${BLUE}Step 3: Create new containers${NC}"
|
||||
docker compose -f docker-compose.dev.yml up -d zookeeper
|
||||
echo "Waiting for Zookeeper to start..."
|
||||
sleep 5
|
||||
|
||||
docker compose -f docker-compose.dev.yml up -d kafka
|
||||
echo "Waiting for Kafka to start..."
|
||||
sleep 20
|
||||
echo -e "${GREEN}✓ Kafka containers created${NC}"
|
||||
echo ""
|
||||
|
||||
# 4. Verify configuration
|
||||
echo -e "${BLUE}Step 4: Verify configuration${NC}"
|
||||
CONTAINER_NAME=$(docker ps --filter "name=presence-kafka" --format "{{.Names}}" | head -1)
|
||||
|
||||
if [ -z "$CONTAINER_NAME" ]; then
|
||||
echo -e "${RED}✗ Kafka container not found${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Container: $CONTAINER_NAME"
|
||||
|
||||
# Check if Kafka is responding
|
||||
if docker exec "$CONTAINER_NAME" nc -z localhost 29092 2>/dev/null; then
|
||||
echo -e "${GREEN}✓ Kafka internal port (29092) is accessible${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ Kafka internal port not yet available${NC}"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# 5. Test external connection
|
||||
echo -e "${BLUE}Step 5: Test Kafka connection${NC}"
|
||||
if nc -zv localhost 9092 2>&1 | grep -q "succeeded\|Connected"; then
|
||||
echo -e "${GREEN}✓ Kafka external port (9092) is accessible${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠️ Kafka external port may need more time to start${NC}"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo -e "${YELLOW}======================================${NC}"
|
||||
echo -e "${GREEN}✓ Kafka rebuild complete!${NC}"
|
||||
echo -e "${YELLOW}======================================${NC}"
|
||||
echo ""
|
||||
echo -e "${BLUE}Next steps:${NC}"
|
||||
echo "1. Start Presence Service: npm run start:dev"
|
||||
echo "2. Run health check: ./scripts/health-check.sh"
|
||||
echo "3. Run quick tests: ./scripts/quick-test.sh"
|
||||
Loading…
Reference in New Issue