#Requires -Version 7.0 param( [ValidateSet('Prepare', 'Stop')] [string] $Action = 'Prepare', [ValidatePattern('^[a-zA-Z0-9][a-zA-Z0-9_-]{0,47}$')] [string] $Session, [ValidateRange(1, 180)] [int] $DurationMinutes = 180 ) $ErrorActionPreference = 'Stop' $demoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path $demoDirectory = Join-Path $demoRoot '.work/course-demo' $demoScript = Join-Path $PSScriptRoot 'prepare_course_demo.py' $demoPython = Join-Path $demoRoot '.venv/Scripts/python.exe' $demoProcessFile = Join-Path $demoDirectory 'sync-process.json' function Stop-DemoSync { if (-not (Test-Path -LiteralPath $demoProcessFile)) { return } $record = Get-Content -LiteralPath $demoProcessFile -Raw | ConvertFrom-Json $process = Get-Process -Id $record.pid -ErrorAction SilentlyContinue if ($null -eq $process) { return } $details = Get-CimInstance Win32_Process -Filter "ProcessId = $($record.pid)" # 仅停止本入口登记且创建时间一致的同步进程,防止 PID 被其他程序复用。 if ($process.StartTime.ToUniversalTime().Ticks -ne [long]$record.started_ticks -or $null -eq $details.CommandLine -or -not $details.CommandLine.Contains($demoScript)) { throw '订单同步进程身份检查失败,请检查进程记录。' } $process.Kill($true) if (-not $process.WaitForExit(10000)) { throw '订单同步进程未在十秒内停止。' } } Push-Location $demoRoot try { if ($Action -eq 'Stop') { Stop-DemoSync Write-Output '课程订单同步已停止,课程数据保留。' return } if (-not (Test-Path -LiteralPath $demoPython)) { throw '请准备项目 Python 环境。' } if (-not $Session) { $Session = Get-Date -Format 'yyyyMMdd-HHmmss-fff' } $env:PYTHONUTF8 = '1' $env:PYTHONIOENCODING = 'utf-8' & $demoPython $demoScript prepare --session $Session if ($LASTEXITCODE -ne 0) { throw '课程订单准备失败。' } # 履约进程读取已登记的专用 OMS 凭据;Compose 保留现有数据库与其他服务。 $env:ZHIFU_RUNTIME_ENV = (Resolve-Path '.work/runtime.env').Path $env:ZHIFU_MODEL_PATH = (Resolve-Path '.work/models').Path docker compose -f compose.runtime.yaml up -d --no-deps fulfillment if ($LASTEXITCODE -ne 0) { throw '履约进程配置加载失败。' } Stop-DemoSync $durationSeconds = $DurationMinutes * 60 $arguments = @(('"' + $demoScript + '"'), 'sync', '--session', $Session, '--duration-seconds', "$durationSeconds", '--interval-seconds', '60') $stdout = Join-Path $demoDirectory "$Session-sync.stdout.log" $stderr = Join-Path $demoDirectory "$Session-sync.stderr.log" $process = Start-Process -FilePath $demoPython -ArgumentList $arguments ` -WorkingDirectory $demoRoot -WindowStyle Hidden -PassThru ` -RedirectStandardOutput $stdout -RedirectStandardError $stderr @{pid = $process.Id; started_ticks = $process.StartTime.ToUniversalTime().Ticks; session = $Session; duration_seconds = $durationSeconds; interval_seconds = 60; stdout = $stdout; stderr = $stderr} | ConvertTo-Json | Set-Content -LiteralPath $demoProcessFile -Encoding utf8 if ($process.WaitForExit(3000)) { Get-Content -LiteralPath $stderr throw '订单同步进程提前结束。' } Write-Output "课程 $Session 已准备;每 60 秒从 OMS 同步一次,最长 $DurationMinutes 分钟。" Write-Output "本次账户及订单:$demoDirectory/active.json" } finally { Pop-Location }