diff --git a/backend/services/deploy-mining.sh b/backend/services/deploy-mining.sh index 33e85229..559c5013 100644 --- a/backend/services/deploy-mining.sh +++ b/backend/services/deploy-mining.sh @@ -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 # 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 [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 [options]" + echo "Usage: $0 [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 [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