#!/usr/bin/env bash set -Eeuo pipefail APP_DIR="${APP_DIR:-/www/wwwroot/wx_service}" DIST_DIR="${DIST_DIR:-${APP_DIR}/dist}" BIN_PATH="${BIN_PATH:-${DIST_DIR}/wx_service}" SOURCE_BIN="${SOURCE_BIN:-}" SERVICE_NAME="${SERVICE_NAME:-wx_service}" PORT="${PORT:-8080}" HEALTH_URL="${HEALTH_URL:-http://127.0.0.1:${PORT}/healthz}" RUN_USER="${RUN_USER:-www}" RUN_GROUP="${RUN_GROUP:-www}" RELEASE_ID="${RELEASE_ID:-manual-$(date +%Y%m%d%H%M%S)}" KEEP_BACKUPS="${KEEP_BACKUPS:-5}" SYNC_CODE="${SYNC_CODE:-false}" DEPLOY_REF="${DEPLOY_REF:-main}" INSTALL_SERVICE="${INSTALL_SERVICE:-true}" log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" } health_check() { local tries=30 while [ "$tries" -gt 0 ]; do if command -v curl >/dev/null 2>&1; then if curl -fsS "$HEALTH_URL" >/dev/null; then return 0 fi else if wget -q -O - "$HEALTH_URL" >/dev/null; then return 0 fi fi tries=$((tries - 1)) sleep 2 done return 1 } restart_service() { if command -v systemctl >/dev/null 2>&1 && systemctl list-unit-files | grep -q "^${SERVICE_NAME}.service"; then log "restarting systemd service: ${SERVICE_NAME}" systemctl restart "$SERVICE_NAME" else log "systemd service not found, fallback to pkill + nohup" pkill -f "$BIN_PATH" || true su -s /bin/bash - "$RUN_USER" -c "cd '$DIST_DIR' && nohup '$BIN_PATH' >> /www/wwwlogs/${SERVICE_NAME}.stdout.log 2>&1 &" fi } create_service_if_needed() { if [ "$INSTALL_SERVICE" != "true" ]; then return 0 fi if ! command -v systemctl >/dev/null 2>&1; then return 0 fi if systemctl list-unit-files | grep -q "^${SERVICE_NAME}.service"; then return 0 fi log "creating systemd service: ${SERVICE_NAME}" cat > "/etc/systemd/system/${SERVICE_NAME}.service" <&2 exit 1 fi if [ ! -f "$SOURCE_BIN" ]; then echo "binary not found: $SOURCE_BIN" >&2 exit 1 fi if [[ "$SOURCE_BIN" == *.gz ]]; then if ! command -v gzip >/dev/null 2>&1; then echo "gzip not found on server" >&2 exit 1 fi decompressed_bin="${SOURCE_BIN%.gz}" log "decompressing binary: ${SOURCE_BIN} -> ${decompressed_bin}" gzip -dc "$SOURCE_BIN" > "$decompressed_bin" chmod 755 "$decompressed_bin" rm -f "$SOURCE_BIN" SOURCE_BIN="$decompressed_bin" fi log "deploy start, release: ${RELEASE_ID}" mkdir -p "$DIST_DIR" "$APP_DIR/backups" if [ "$SYNC_CODE" = "true" ] && [ -d "$APP_DIR/.git" ]; then log "syncing code from github ref: ${DEPLOY_REF}" git -C "$APP_DIR" fetch --all --prune git -C "$APP_DIR" reset --hard "$DEPLOY_REF" fi backup_path="" if [ -f "$BIN_PATH" ]; then backup_path="$APP_DIR/backups/wx_service.${RELEASE_ID}.bak" cp -f "$BIN_PATH" "$backup_path" log "backup created: $backup_path" fi install -m 755 "$SOURCE_BIN" "${BIN_PATH}.new" mv -f "${BIN_PATH}.new" "$BIN_PATH" chown "$RUN_USER:$RUN_GROUP" "$BIN_PATH" || true if [ ! -f "$DIST_DIR/.env" ] && [ -f "$APP_DIR/.env" ]; then cp -f "$APP_DIR/.env" "$DIST_DIR/.env" chown "$RUN_USER:$RUN_GROUP" "$DIST_DIR/.env" || true fi create_service_if_needed restart_service if health_check; then log "health check success: $HEALTH_URL" else log "health check failed, rollback" if [ -n "$backup_path" ] && [ -f "$backup_path" ]; then cp -f "$backup_path" "$BIN_PATH" chown "$RUN_USER:$RUN_GROUP" "$BIN_PATH" || true restart_service || true fi exit 1 fi if [ -f "$SOURCE_BIN" ] && [[ "$SOURCE_BIN" == /tmp/* ]]; then rm -f "$SOURCE_BIN" fi if [ -d "$APP_DIR/backups" ]; then ls -1t "$APP_DIR"/backups/wx_service.*.bak 2>/dev/null | tail -n +$((KEEP_BACKUPS + 1)) | xargs -r rm -f fi log "deploy done"