feat(mining): 增强部署脚本支持单服务操作

## 新增功能

### 单服务操作
- `up [service]` - 启动全部或指定服务
- `down [service]` - 停止全部或指定服务
- `restart [service]` - 重启全部或指定服务
- `build [service] [--no-cache]` - 构建全部或指定服务
- `rebuild [service]` - 等同于 build --no-cache

### 服务别名
- `contrib`, `contribution` -> contribution-service
- `mining` -> mining-service
- `trading` -> trading-service
- `admin` -> mining-admin-service

### 单服务数据库操作
- `db-create [service]` - 创建全部或指定服务的数据库
- `db-migrate [service]` - 运行全部或指定服务的迁移
- `db-reset [service]` - 重置全部或指定服务的数据库

### 构建功能增强
- `--no-cache` 选项清除 dist/ 和 node_modules/.cache
- 自动运行 npm install
- 自动生成 Prisma client
- 编译 TypeScript

### 状态显示增强
- 显示服务 PID
- 通过端口检测运行状态
- 健康检查端点验证

## 使用示例

```bash
./deploy-mining.sh up mining          # 仅启动 mining-service
./deploy-mining.sh restart contrib    # 重启 contribution-service
./deploy-mining.sh build trading --no-cache  # 清除缓存重新构建
./deploy-mining.sh logs admin 200     # 查看最后200行日志
./deploy-mining.sh db-reset mining    # 仅重置 mining-service 数据库
```

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-01-10 18:12:38 -08:00
parent 7c3bf4f068
commit c8c2e63da6
1 changed files with 419 additions and 98 deletions

View File

@ -8,12 +8,13 @@
# affecting the 1.0 system.
#
# Usage:
# ./deploy-mining.sh up # Start all 2.0 services
# ./deploy-mining.sh down # Stop all 2.0 services
# ./deploy-mining.sh restart # Restart all 2.0 services
# ./deploy-mining.sh status # Show 2.0 service status
# ./deploy-mining.sh logs [service] # View logs (optional: specific service)
# ./deploy-mining.sh build # Rebuild all 2.0 images
# ./deploy-mining.sh up [service] # Start all or specific service
# ./deploy-mining.sh down [service] # Stop all or specific service
# ./deploy-mining.sh restart [service] # Restart all or specific service
# ./deploy-mining.sh status # Show 2.0 service status
# ./deploy-mining.sh logs <service> # View logs for specific service
# ./deploy-mining.sh build [service] [--no-cache] # Build all or specific service
# ./deploy-mining.sh rebuild [service] # Rebuild with --no-cache
#
# Database Management:
# ./deploy-mining.sh db-create # Create 2.0 databases
@ -24,7 +25,6 @@
# CDC & Sync:
# ./deploy-mining.sh sync-reset # Reset CDC consumer offsets to beginning
# ./deploy-mining.sh sync-status # Show CDC consumer group status
# ./deploy-mining.sh sync-start # Start CDC sync from current position
#
# Full Reset (for development/testing):
# ./deploy-mining.sh full-reset # Complete reset: stop services, drop DBs, recreate, resync
@ -33,6 +33,12 @@
# ./deploy-mining.sh health # Check health of all 2.0 services
# ./deploy-mining.sh stats # Show system statistics
#
# Service Aliases:
# contrib, contribution -> contribution-service
# mining -> mining-service
# trading -> trading-service
# admin -> mining-admin-service
#
set -e
@ -41,6 +47,7 @@ set -e
# ===========================================================================
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ENV_FILE="$SCRIPT_DIR/.env"
COMPOSE_FILE="$SCRIPT_DIR/docker-compose.yml"
# 2.0 Services
MINING_SERVICES=(
@ -50,6 +57,15 @@ MINING_SERVICES=(
"mining-admin-service"
)
# Service Aliases
declare -A SERVICE_ALIASES=(
["contrib"]="contribution-service"
["contribution"]="contribution-service"
["mining"]="mining-service"
["trading"]="trading-service"
["admin"]="mining-admin-service"
)
# 2.0 Databases
MINING_DATABASES=(
"rwa_contribution"
@ -58,6 +74,14 @@ MINING_DATABASES=(
"rwa_mining_admin"
)
# Service to Database mapping
declare -A SERVICE_DB=(
["contribution-service"]="rwa_contribution"
["mining-service"]="rwa_mining"
["trading-service"]="rwa_trading"
["mining-admin-service"]="rwa_mining_admin"
)
# 2.0 Ports
declare -A SERVICE_PORTS=(
["contribution-service"]="3020"
@ -102,6 +126,68 @@ print_section() {
echo ""
}
# ===========================================================================
# Helper Functions
# ===========================================================================
resolve_service_name() {
local input="$1"
# Check if it's an alias
if [ -n "${SERVICE_ALIASES[$input]:-}" ]; then
echo "${SERVICE_ALIASES[$input]}"
return 0
fi
# Check if it's a valid service name
for service in "${MINING_SERVICES[@]}"; do
if [ "$service" = "$input" ]; then
echo "$service"
return 0
fi
done
# Not found
return 1
}
validate_service() {
local service="$1"
for s in "${MINING_SERVICES[@]}"; do
if [ "$s" = "$service" ]; then
return 0
fi
done
return 1
}
get_services_to_process() {
local input="$1"
if [ -z "$input" ]; then
# Return all services
echo "${MINING_SERVICES[@]}"
else
# Resolve and return single service
local resolved
resolved=$(resolve_service_name "$input") || {
log_error "Unknown service: $input"
echo ""
echo "Available services:"
for service in "${MINING_SERVICES[@]}"; do
echo " - $service (port ${SERVICE_PORTS[$service]})"
done
echo ""
echo "Aliases:"
echo " - contrib, contribution -> contribution-service"
echo " - mining -> mining-service"
echo " - trading -> trading-service"
echo " - admin -> mining-admin-service"
exit 1
}
echo "$resolved"
fi
}
# ===========================================================================
# Environment Loading
# ===========================================================================
@ -128,9 +214,17 @@ load_env() {
# Database Functions
# ===========================================================================
db_create() {
local target_service="$1"
print_section "Creating 2.0 Databases"
for db in "${MINING_DATABASES[@]}"; do
local dbs_to_create=()
if [ -n "$target_service" ]; then
dbs_to_create=("${SERVICE_DB[$target_service]}")
else
dbs_to_create=("${MINING_DATABASES[@]}")
fi
for db in "${dbs_to_create[@]}"; do
log_step "Creating database: $db"
PGPASSWORD="$POSTGRES_PASSWORD" psql -h "$POSTGRES_HOST" -p "$POSTGRES_PORT" -U "$POSTGRES_USER" -d postgres -c "CREATE DATABASE $db;" 2>/dev/null || {
log_warn "Database $db already exists or creation failed"
@ -141,9 +235,17 @@ db_create() {
}
db_drop() {
local target_service="$1"
print_section "Dropping 2.0 Databases"
for db in "${MINING_DATABASES[@]}"; do
local dbs_to_drop=()
if [ -n "$target_service" ]; then
dbs_to_drop=("${SERVICE_DB[$target_service]}")
else
dbs_to_drop=("${MINING_DATABASES[@]}")
fi
for db in "${dbs_to_drop[@]}"; do
log_step "Dropping database: $db"
PGPASSWORD="$POSTGRES_PASSWORD" psql -h "$POSTGRES_HOST" -p "$POSTGRES_PORT" -U "$POSTGRES_USER" -d postgres -c "DROP DATABASE IF EXISTS $db WITH (FORCE);" 2>/dev/null || {
log_warn "Failed to drop database $db"
@ -154,9 +256,17 @@ db_drop() {
}
db_migrate() {
local target_service="$1"
print_section "Running Prisma Migrations"
for service in "${MINING_SERVICES[@]}"; do
local services_to_migrate=()
if [ -n "$target_service" ]; then
services_to_migrate=("$target_service")
else
services_to_migrate=("${MINING_SERVICES[@]}")
fi
for service in "${services_to_migrate[@]}"; do
service_dir="$SCRIPT_DIR/$service"
if [ -d "$service_dir/prisma" ]; then
log_step "Migrating: $service"
@ -186,11 +296,20 @@ db_status() {
}
db_reset() {
local target_service="$1"
print_section "Resetting 2.0 Databases"
echo -e "${RED}${BOLD}WARNING: This will DELETE ALL 2.0 DATA!${NC}"
local dbs_to_reset=()
if [ -n "$target_service" ]; then
dbs_to_reset=("${SERVICE_DB[$target_service]}")
echo -e "${RED}${BOLD}WARNING: This will DELETE data for $target_service!${NC}"
else
dbs_to_reset=("${MINING_DATABASES[@]}")
echo -e "${RED}${BOLD}WARNING: This will DELETE ALL 2.0 DATA!${NC}"
fi
echo "Affected databases:"
for db in "${MINING_DATABASES[@]}"; do
for db in "${dbs_to_reset[@]}"; do
echo " - $db"
done
echo ""
@ -201,71 +320,239 @@ db_reset() {
return 1
fi
db_drop
db_create
db_migrate
db_drop "$target_service"
db_create "$target_service"
db_migrate "$target_service"
log_success "Database reset completed"
}
# ===========================================================================
# Service Functions
# Single Service Functions
# ===========================================================================
service_start() {
local service="$1"
local port="${SERVICE_PORTS[$service]}"
log_step "Starting: $service (port $port)"
# Try docker-compose first
if docker-compose -f "$COMPOSE_FILE" up -d "$service" 2>/dev/null; then
log_success "$service started via docker-compose"
return 0
fi
# Fallback to npm
local service_dir="$SCRIPT_DIR/$service"
if [ -d "$service_dir" ]; then
cd "$service_dir"
# Check if already running
if [ -f "/tmp/$service.pid" ]; then
local pid=$(cat /tmp/$service.pid)
if kill -0 "$pid" 2>/dev/null; then
log_warn "$service is already running (PID: $pid)"
cd "$SCRIPT_DIR"
return 0
fi
fi
# Start the service
log_info "Starting via npm..."
nohup npm run start:prod > "/tmp/$service.log" 2>&1 &
echo $! > "/tmp/$service.pid"
# Wait for startup
sleep 2
if nc -z localhost "$port" 2>/dev/null; then
log_success "$service started (PID: $(cat /tmp/$service.pid))"
else
log_warn "$service started but port $port not yet listening"
fi
cd "$SCRIPT_DIR"
else
log_error "Service directory not found: $service_dir"
return 1
fi
}
service_stop() {
local service="$1"
log_step "Stopping: $service"
# Try docker-compose first
if docker-compose -f "$COMPOSE_FILE" stop "$service" 2>/dev/null; then
log_success "$service stopped via docker-compose"
return 0
fi
# Fallback to PID file
if [ -f "/tmp/$service.pid" ]; then
local pid=$(cat /tmp/$service.pid)
if kill "$pid" 2>/dev/null; then
rm -f "/tmp/$service.pid"
log_success "$service stopped (PID: $pid)"
else
rm -f "/tmp/$service.pid"
log_warn "$service was not running"
fi
else
# Try to find by port
local port="${SERVICE_PORTS[$service]}"
local pid=$(lsof -t -i:$port 2>/dev/null || true)
if [ -n "$pid" ]; then
kill "$pid" 2>/dev/null || true
log_success "$service stopped (found by port $port)"
else
log_warn "$service was not running"
fi
fi
}
service_restart() {
local service="$1"
service_stop "$service"
sleep 2
service_start "$service"
}
service_build() {
local service="$1"
local no_cache="$2"
local service_dir="$SCRIPT_DIR/$service"
if [ ! -d "$service_dir" ]; then
log_error "Service directory not found: $service_dir"
return 1
fi
log_step "Building: $service"
cd "$service_dir"
# Clean if no-cache
if [ "$no_cache" = "--no-cache" ] || [ "$no_cache" = "true" ]; then
log_info "Cleaning build cache..."
rm -rf dist/ node_modules/.cache 2>/dev/null || true
fi
# Install dependencies
log_info "Installing dependencies..."
npm install
# Generate Prisma client if needed
if [ -d "prisma" ]; then
log_info "Generating Prisma client..."
npx prisma generate
fi
# Build
log_info "Compiling TypeScript..."
npm run build
cd "$SCRIPT_DIR"
log_success "$service built successfully"
}
service_rebuild() {
local service="$1"
service_build "$service" "--no-cache"
}
# ===========================================================================
# Batch Service Functions
# ===========================================================================
services_up() {
local target="$1"
print_section "Starting 2.0 Services"
for service in "${MINING_SERVICES[@]}"; do
log_step "Starting: $service"
docker-compose -f "$SCRIPT_DIR/docker-compose.yml" up -d "$service" 2>/dev/null || {
log_warn "$service not in docker-compose, trying npm start"
service_dir="$SCRIPT_DIR/$service"
if [ -d "$service_dir" ]; then
cd "$service_dir"
nohup npm run start:prod > /tmp/$service.log 2>&1 &
echo $! > /tmp/$service.pid
cd "$SCRIPT_DIR"
fi
}
local services
services=$(get_services_to_process "$target")
[ -z "$services" ] && exit 1
for service in $services; do
service_start "$service"
done
log_success "Services started"
log_success "Service startup completed"
}
services_down() {
local target="$1"
print_section "Stopping 2.0 Services"
for service in "${MINING_SERVICES[@]}"; do
log_step "Stopping: $service"
docker-compose -f "$SCRIPT_DIR/docker-compose.yml" stop "$service" 2>/dev/null || {
if [ -f "/tmp/$service.pid" ]; then
kill $(cat /tmp/$service.pid) 2>/dev/null || true
rm -f /tmp/$service.pid
fi
}
local services
services=$(get_services_to_process "$target")
[ -z "$services" ] && exit 1
for service in $services; do
service_stop "$service"
done
log_success "Services stopped"
}
services_restart() {
services_down
sleep 2
services_up
local target="$1"
print_section "Restarting 2.0 Services"
local services
services=$(get_services_to_process "$target")
[ -z "$services" ] && exit 1
for service in $services; do
service_restart "$service"
done
log_success "Services restarted"
}
services_build() {
local target="$1"
local no_cache="$2"
print_section "Building 2.0 Services"
local services
services=$(get_services_to_process "$target")
[ -z "$services" ] && exit 1
for service in $services; do
service_build "$service" "$no_cache"
done
log_success "Build completed"
}
services_rebuild() {
local target="$1"
services_build "$target" "--no-cache"
}
services_status() {
print_section "2.0 Service Status"
echo -e "${BOLD}Service${NC}\t\t\t${BOLD}Port${NC}\t${BOLD}Status${NC}\t\t${BOLD}Health${NC}"
echo "────────────────────────────────────────────────────────────────"
echo -e "${BOLD}Service${NC}\t\t\t${BOLD}Port${NC}\t${BOLD}Status${NC}\t\t${BOLD}Health${NC}\t\t${BOLD}PID${NC}"
echo "────────────────────────────────────────────────────────────────────────"
for service in "${MINING_SERVICES[@]}"; do
port="${SERVICE_PORTS[$service]}"
pid="-"
# Get PID
if [ -f "/tmp/$service.pid" ]; then
pid=$(cat /tmp/$service.pid 2>/dev/null || echo "-")
fi
# Check if port is listening
if nc -z localhost "$port" 2>/dev/null; then
status="${GREEN}RUNNING${NC}"
# Get PID from port if not in file
if [ "$pid" = "-" ]; then
pid=$(lsof -t -i:$port 2>/dev/null | head -1 || echo "-")
fi
# Check health endpoint
health_response=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:$port/health" 2>/dev/null || echo "000")
if [ "$health_response" = "200" ]; then
@ -276,44 +563,49 @@ services_status() {
else
status="${RED}STOPPED${NC}"
health="${RED}-${NC}"
pid="-"
fi
echo -e "$service\t$port\t$status\t$health"
echo -e "$service\t$port\t$status\t$health\t\t$pid"
done
}
services_logs() {
local service="$1"
local lines="${2:-100}"
if [ -n "$service" ]; then
docker-compose -f "$SCRIPT_DIR/docker-compose.yml" logs -f "$service" 2>/dev/null || {
if [ -f "/tmp/$service.log" ]; then
tail -f "/tmp/$service.log"
else
log_error "No logs found for $service"
fi
}
else
if [ -z "$service" ]; then
log_error "Please specify a service name"
echo ""
echo "Usage: $0 logs <service> [lines]"
echo ""
echo "Available services:"
for svc in "${MINING_SERVICES[@]}"; do
docker-compose -f "$SCRIPT_DIR/docker-compose.yml" logs --tail=50 "$svc" 2>/dev/null || true
echo " - $svc"
done
exit 1
fi
}
services_build() {
print_section "Building 2.0 Services"
local resolved
resolved=$(resolve_service_name "$service") || {
log_error "Unknown service: $service"
exit 1
}
for service in "${MINING_SERVICES[@]}"; do
service_dir="$SCRIPT_DIR/$service"
if [ -d "$service_dir" ]; then
log_step "Building: $service"
cd "$service_dir"
npm run build
cd "$SCRIPT_DIR"
fi
done
# Try docker-compose first
if docker-compose -f "$COMPOSE_FILE" logs -f --tail="$lines" "$resolved" 2>/dev/null; then
return 0
fi
log_success "Build completed"
# Fallback to log file
local log_file="/tmp/$resolved.log"
if [ -f "$log_file" ]; then
log_info "Showing logs for $resolved (tail -f $log_file)"
tail -f -n "$lines" "$log_file"
else
log_error "No logs found for $resolved"
exit 1
fi
}
# ===========================================================================
@ -334,7 +626,7 @@ sync_reset() {
# Stop contribution-service first
log_step "Stopping contribution-service"
docker-compose -f "$SCRIPT_DIR/docker-compose.yml" stop contribution-service 2>/dev/null || true
service_stop "contribution-service"
# Reset offsets
log_step "Resetting consumer group offsets"
@ -400,7 +692,9 @@ full_reset() {
echo ""
log_step "Step 1/6: Stopping 2.0 services..."
services_down
for service in "${MINING_SERVICES[@]}"; do
service_stop "$service"
done
log_step "Step 2/6: Dropping 2.0 databases..."
db_drop
@ -427,7 +721,9 @@ full_reset() {
}
log_step "Step 6/6: Starting 2.0 services..."
services_up
for service in "${MINING_SERVICES[@]}"; do
service_start "$service"
done
echo ""
echo -e "${GREEN}${BOLD}╔════════════════════════════════════════════════════════════╗${NC}"
@ -529,43 +825,53 @@ show_stats() {
show_help() {
print_header
echo "Usage: $0 <command> [options]"
echo "Usage: $0 <command> [service] [options]"
echo ""
echo -e "${BOLD}Service Management:${NC}"
echo " up Start all 2.0 services"
echo " down Stop all 2.0 services"
echo " restart Restart all 2.0 services"
echo " status Show service status"
echo " logs [service] View logs (optionally for specific service)"
echo " build Build all 2.0 services"
echo " up [service] Start all or specific service"
echo " down [service] Stop all or specific service"
echo " restart [service] Restart all or specific service"
echo " status Show all service status"
echo " logs <service> [lines] View logs for specific service"
echo " build [service] [--no-cache] Build all or specific service"
echo " rebuild [service] Rebuild with --no-cache"
echo ""
echo -e "${BOLD}Database Management:${NC}"
echo " db-create Create 2.0 databases"
echo " db-migrate Run Prisma migrations"
echo " db-reset Drop and recreate databases ${RED}(DANGEROUS!)${NC}"
echo " db-status Show database status"
echo " db-create [service] Create databases (all or for specific service)"
echo " db-migrate [service] Run Prisma migrations"
echo " db-reset [service] Drop and recreate databases ${RED}(DANGEROUS!)${NC}"
echo " db-status Show database status"
echo ""
echo -e "${BOLD}CDC / Sync Management:${NC}"
echo " sync-reset Reset CDC consumer to read from beginning"
echo " sync-status Show CDC consumer group status"
echo " sync-reset Reset CDC consumer to read from beginning"
echo " sync-status Show CDC consumer group status"
echo ""
echo -e "${BOLD}Full Reset:${NC}"
echo " full-reset Complete system reset ${RED}(DANGEROUS!)${NC}"
echo " Drops DBs, resets CDC, restarts services"
echo " full-reset Complete system reset ${RED}(DANGEROUS!)${NC}"
echo " Drops DBs, resets CDC, restarts services"
echo ""
echo -e "${BOLD}Health & Monitoring:${NC}"
echo " health Check health of all 2.0 components"
echo " stats Show system statistics"
echo " health Check health of all 2.0 components"
echo " stats Show system statistics"
echo ""
echo -e "${BOLD}2.0 Services:${NC}"
for service in "${MINING_SERVICES[@]}"; do
echo " - $service (port ${SERVICE_PORTS[$service]})"
done
echo ""
echo -e "${BOLD}2.0 Databases:${NC}"
for db in "${MINING_DATABASES[@]}"; do
echo " - $db"
done
echo -e "${BOLD}Service Aliases:${NC}"
echo " contrib, contribution -> contribution-service"
echo " mining -> mining-service"
echo " trading -> trading-service"
echo " admin -> mining-admin-service"
echo ""
echo -e "${BOLD}Examples:${NC}"
echo " $0 up # Start all services"
echo " $0 up mining # Start only mining-service"
echo " $0 restart contrib # Restart contribution-service"
echo " $0 build trading --no-cache # Rebuild trading-service"
echo " $0 logs admin 200 # Show last 200 lines of admin logs"
echo " $0 db-reset mining # Reset only mining-service database"
echo ""
echo -e "${YELLOW}Note: The 2.0 system is completely isolated from 1.0.${NC}"
echo -e "${YELLOW}Any reset operation will NOT affect the 1.0 system.${NC}"
@ -580,34 +886,49 @@ main() {
case "${1:-}" in
# Service commands
up)
services_up
services_up "$2"
;;
down)
services_down
services_down "$2"
;;
restart)
services_restart
services_restart "$2"
;;
status)
print_header
services_status
;;
logs)
services_logs "$2"
services_logs "$2" "$3"
;;
build)
services_build
services_build "$2" "$3"
;;
rebuild)
services_rebuild "$2"
;;
# Database commands
db-create)
db_create
if [ -n "$2" ]; then
resolved=$(resolve_service_name "$2") && db_create "$resolved"
else
db_create
fi
;;
db-migrate)
db_migrate
if [ -n "$2" ]; then
resolved=$(resolve_service_name "$2") && db_migrate "$resolved"
else
db_migrate
fi
;;
db-reset)
db_reset
if [ -n "$2" ]; then
resolved=$(resolve_service_name "$2") && db_reset "$resolved"
else
db_reset
fi
;;
db-status)
print_header