param( [string]$BackupVersion = $null ) $ErrorActionPreference = "Stop" $configPath = "D:\EPproject\LabelReplaceServer\deployment\config\deployment-config.json" $stateFile = "D:\EPproject\LabelReplaceServer\deployment\instance_state.json" $logFile = "D:\EPproject\LabelReplaceServer\deployment\logs\deployment.log" $backupDir = "D:\EPproject\LabelReplaceServer\deployment\backups" function Log { param([string]$Message, [string]$Level = "INFO") $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $logEntry = "[$timestamp] [$Level] [Rollback] $Message" Write-Host $logEntry -ForegroundColor $(switch($Level) { "ERROR" { "Red" } "WARN" { "Yellow" } "INFO" { "Green" } default { "White" } }) $logDirPath = Split-Path -Parent $logFile if (!(Test-Path $logDirPath)) { New-Item -ItemType Directory -Path $logDirPath -Force | Out-Null } Add-Content -Path $logFile -Value $logEntry } function GetLatestBackup { if (!(Test-Path $backupDir)) { return $null } $backups = Get-ChildItem -Path $backupDir -Directory | Sort-Object -Property LastWriteTime -Descending return $backups[0] } function RestoreFromBackup { param([string]$BackupPath, [string]$TargetPath) Log "从备份恢复: $BackupPath -> $TargetPath" "INFO" if (Test-Path $TargetPath) { Log "移除现有实例目录..." "INFO" Remove-Item -Path $TargetPath -Recurse -Force } Copy-Item -Path $BackupPath -Destination $TargetPath -Recurse -Force Log "已从备份恢复文件" "INFO" } function StartInstance { param([string]$Instance, [string]$Directory, [int]$Port) Log "启动 $Instance 实例 (端口: $Port)..." "INFO" try { $exePath = Join-Path $Directory "CONTROLLER.exe" $env:DEPLOYMENT_INSTANCE = if ($Instance -eq "green") { "green" } else { "blue" } $env:SHUTDOWN_TIMEOUT = "30" $process = Start-Process -FilePath $exePath -WorkingDirectory $Directory -PassThru Log "$Instance 实例已启动 (PID: $($process.Id))" "INFO" Start-Sleep -Seconds 2 return $process.Id } catch { Log "启动实例失败: $_" "ERROR" throw } } function StopInstance { param([int]$GracefulTimeout = 30) try { $controller = Get-Process -Name CONTROLLER -ErrorAction SilentlyContinue if ($null -eq $controller) { Log "CONTROLLER 进程未找到" "WARN" return $true } Log "停止 CONTROLLER 进程 (PID: $($controller.Id))..." "INFO" if ($controller.WaitForExit($GracefulTimeout * 1000)) { Log "进程已退出" "INFO" return $true } Log "强制终止进程..." "WARN" $controller | Stop-Process -Force return $true } catch { Log "停止实例失败: $_" "ERROR" return $false } } try { Log "========================================" "INFO" Log "开始回滚流程" "INFO" Log "========================================" "INFO" if (!(Test-Path $configPath)) { throw "配置文件不存在: $configPath" } $config = Get-Content $configPath | ConvertFrom-Json if (!(Test-Path $stateFile)) { throw "状态文件不存在: $stateFile,无法确定当前实例" } $state = Get-Content $stateFile | ConvertFrom-Json $currentInstance = $state.activeInstance $previousInstance = if ($currentInstance -eq "blue") { "green" } else { "blue" } Log "当前活跃实例: $currentInstance" "INFO" Log "回滚目标实例: $previousInstance" "INFO" $backup = GetLatestBackup if ($null -eq $backup) { throw "没有找到备份文件" } Log "最新备份: $($backup.Name)" "INFO" $previousConfig = if ($previousInstance -eq "green") { $config.GreenInstance } else { $config.BlueInstance } Log "========== 第一步:停止当前实例 ==========" "INFO" StopInstance -GracefulTimeout 30 Log "========== 第二步:恢复备份 ==========" "INFO" RestoreFromBackup -BackupPath $backup.FullName -TargetPath $previousConfig.Directory Log "========== 第三步:启动恢复的实例 ==========" "INFO" $pid = StartInstance -Instance $previousInstance -Directory $previousConfig.Directory ` -Port $previousConfig.Port Log "========== 第四步:健康检查 ==========" "INFO" $healthScript = "D:\EPproject\LabelReplaceServer\deployment\scripts\health-check.ps1" $healthResult = & $healthScript -Instance $previousInstance -Port $previousConfig.Port if (!$healthResult) { throw "恢复的实例健康检查失败" } Log "========== 第五步:更新活跃实例 ==========" "INFO" $newState = @{ activeInstance = $previousInstance lastUpdate = Get-Date -Format "yyyy-MM-dd HH:mm:ss" version = $state.version rolledBack = $true } $newState | ConvertTo-Json | Set-Content -Path $stateFile -Force Log "========================================" "INFO" Log "回滚完成!" "INFO" Log "新活跃实例: $previousInstance (端口: $($previousConfig.Port))" "INFO" Log "========================================" "INFO" } catch { Log "回滚失败: $_" "ERROR" Log "错误详情: $($_.Exception.StackTrace)" "ERROR" exit 1 }