From 707ca8e508adc0afe0d9490a9a711b2a2f6fbad0 Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Sat, 8 Aug 2026 10:11:36 +0800 Subject: [PATCH] fix(lab): avoid PostgreSQL pipeline deadlock [T-014] --- Sense/scripts/t014-capacity.ps1 | 28 ++++++++++++++++++++------- tests/test_sense_capacity_contract.py | 2 ++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/Sense/scripts/t014-capacity.ps1 b/Sense/scripts/t014-capacity.ps1 index 7ecdd33..585ba8d 100644 --- a/Sense/scripts/t014-capacity.ps1 +++ b/Sense/scripts/t014-capacity.ps1 @@ -128,14 +128,23 @@ function Stop-ManagedProcess($Managed) { function Stop-AllManagedProcesses($Items) { $processes = @($Items | Where-Object { $null -ne $_ -and $null -ne $_.Process }) foreach ($item in $processes) { - if (-not $item.Process.HasExited) { - $item.Process.Kill() + try { + if (-not $item.Process.HasExited) { + $item.Process.Kill() + } + } + catch { + if (-not $item.Process.HasExited) { throw } } } - foreach ($item in $processes) { - if (-not $item.Process.HasExited) { - $item.Process.WaitForExit(10000) | Out-Null - } + $cleanupWatch = [Diagnostics.Stopwatch]::StartNew() + while ($cleanupWatch.Elapsed.TotalSeconds -lt 10 -and + @($processes | Where-Object { -not $_.Process.HasExited }).Count -gt 0) { + Start-Sleep -Milliseconds 100 + } + $remaining = @($processes | Where-Object { -not $_.Process.HasExited }) + if ($remaining.Count -gt 0) { + Write-Warning "managed processes did not exit within the shared cleanup deadline: $($remaining.Count)" } } @@ -607,7 +616,12 @@ try { New-Item -ItemType Directory -Path $pgData | Out-Null Invoke-Checked $script:initdb '-D' $pgData '-U' 'postgres' '-A' 'trust' '--encoding=UTF8' '--no-locale' '--no-sync' $serverOptions = "-h 127.0.0.1 -p $postgresPort -c listen_addresses=127.0.0.1" - Invoke-Checked $script:pgCtl '-D' $pgData '-l' $pgLog '-o' $serverOptions '-w' 'start' + # Do not pipe pg_ctl start output: postgres can inherit the pipeline handle and + # keep PowerShell waiting until the server exits. + & $script:pgCtl '-D' $pgData '-l' $pgLog '-o' $serverOptions '-w' 'start' + if ($LASTEXITCODE -ne 0) { + throw "required command failed with exit code $LASTEXITCODE" + } $postgresStarted = $true Invoke-Checked $script:psql '-X' '-v' 'ON_ERROR_STOP=1' '-d' $adminRootDSN '-f' (Join-Path $script:repoRoot 'deploy\postgres\001_roles.sql') Invoke-Checked $script:createdb '-h' '127.0.0.1' '-p' ([string]$postgresPort) '-U' 'postgres' $databaseName diff --git a/tests/test_sense_capacity_contract.py b/tests/test_sense_capacity_contract.py index 319bc90..e80112a 100644 --- a/tests/test_sense_capacity_contract.py +++ b/tests/test_sense_capacity_contract.py @@ -44,6 +44,8 @@ class SenseCapacityContractTests(unittest.TestCase): self.assertIn("yovision-t014", self.script) self.assertIn("[IO.Path]::GetFileName($resolvedSession) -notlike 'session-*'", self.script) self.assertIn("the existing PostgreSQL listener on port 5432 changed", self.script) + self.assertNotRegex(self.script, r"Invoke-Checked \$script:pgCtl .* 'start'") + self.assertIn("$cleanupWatch.Elapsed.TotalSeconds -lt 10", self.script) def test_runtime_secrets_and_sensitive_inventory_are_not_reported(self): self.assertIn("New-SecretToken", self.script)