180 lines
5.5 KiB
PowerShell
180 lines
5.5 KiB
PowerShell
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
|
|
}
|