Skip to content

Commit 3c1d910

Browse files
committed
Harden FlowChain service port handoff
1 parent 3d0d5d8 commit 3c1d910

7 files changed

Lines changed: 70 additions & 29 deletions

File tree

docs/agent-runs/live-product-dev-pack/DEV_PACK.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
Status: `passed`
44

5-
Generated at: `2026-05-16T13:58:15.301Z`
5+
Generated at: `2026-05-16T14:01:55.638Z`
66
Checks: `9/9`
77
Method count: `79`
88
Public-ready method count: `0`
9-
Height: `37971 -> 37972`
9+
Height: `38020 -> 38021`
1010

1111
## Remaining Live Inputs
1212

docs/agent-runs/live-product-dev-pack/dev-pack-e2e-report.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"schema": "flowchain.dev_pack_e2e_report.v0",
3-
"generatedAt": "2026-05-16T13:58:15.301Z",
3+
"generatedAt": "2026-05-16T14:01:55.638Z",
44
"status": "passed",
55
"rpcUrl": "http://127.0.0.1:8787/rpc",
66
"checks": {
@@ -16,8 +16,8 @@
1616
},
1717
"methodCount": 79,
1818
"publicReadyMethodCount": 0,
19-
"firstHeight": "37971",
20-
"secondHeight": "37972",
19+
"firstHeight": "38020",
20+
"secondHeight": "38021",
2121
"missingEnvNames": [
2222
"FLOWCHAIN_BASE8453_FROM_BLOCK",
2323
"FLOWCHAIN_BASE8453_LOCKBOX_ADDRESS",

docs/agent-runs/live-product-infra-rpc/service-restart-report.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"schema": "flowchain.service_restart_report.v0",
3-
"generatedAt": "2026-05-16T13:12:19.3856849Z",
3+
"generatedAt": "2026-05-16T14:00:56.8591408Z",
44
"status": "passed",
55
"statePreserved": true,
66
"deletedRuntimeData": false,

docs/agent-runs/live-product-infra-rpc/service-status-report.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"schema": "flowchain.service_status_report.v0",
3-
"generatedAt": "2026-05-16T13:46:48.8941026Z",
3+
"generatedAt": "2026-05-16T14:01:31.2983104Z",
44
"status": "passed",
55
"bind": {
66
"host": "127.0.0.1",
@@ -9,13 +9,13 @@
99
},
1010
"node": {
1111
"status": "running",
12-
"pid": 48568,
12+
"pid": 58172,
1313
"pidPath": "devnet/local/node/flowchain-node.pid",
1414
"commandLineMatched": true
1515
},
1616
"controlPlane": {
1717
"status": "running",
18-
"pid": 25276,
18+
"pid": 52292,
1919
"pidPath": "devnet/local/services/control-plane.pid",
2020
"commandLineMatched": true
2121
},
@@ -39,12 +39,12 @@
3939
},
4040
"chain": {
4141
"stateFileReadable": true,
42-
"latestHeight": "37767",
43-
"latestHash": "0x5f76384d4b813f5a0ff4304a14c61c26224d874109b055a660b22866718acf13",
42+
"latestHeight": "38011",
43+
"latestHash": "0xaf6bf563b8f8e6e07692e4eac84ffb7c3bf4a7053f02dea837dfd316244a069b",
4444
"latestRoot": "0x794b020b793262b13d2b1a8d2a2778e0ed5f4f7546b8cc631b85ae65df503913",
45-
"stateFileLastWriteAgeSeconds": 4,
46-
"finalizedHeight": "37767",
47-
"finalizedHash": "0x5f76384d4b813f5a0ff4304a14c61c26224d874109b055a660b22866718acf13",
45+
"stateFileLastWriteAgeSeconds": 3,
46+
"finalizedHeight": "38011",
47+
"finalizedHash": "0xaf6bf563b8f8e6e07692e4eac84ffb7c3bf4a7053f02dea837dfd316244a069b",
4848
"mempoolDepth": 0,
4949
"peerCount": null
5050
},

docs/agent-runs/live-product-infra-rpc/service-stop-report.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
{
22
"schema": "flowchain.service_stop_report.v0",
3-
"generatedAt": "2026-05-16T13:11:20.7805940Z",
3+
"generatedAt": "2026-05-16T14:00:04.7422041Z",
44
"status": "stopped",
55
"node": "stop-requested",
6-
"controlPlane": "not-running",
6+
"controlPlane": "stopped",
77
"bridgeRelayerLoop": "not-running",
88
"statePreserved": true,
99
"deletedRuntimeData": false,

infra/scripts/flowchain-service-start.ps1

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,48 @@ function Get-ControlPlanePortProcess {
4848
return $null
4949
}
5050
$pidValue = [int]$connections[0].OwningProcess
51-
try {
52-
$commandLine = (Get-CimInstance Win32_Process -Filter "ProcessId=$pidValue").CommandLine
53-
}
54-
catch {
55-
$commandLine = ""
51+
$commandLine = ""
52+
if ($pidValue -gt 0) {
53+
try {
54+
$commandLine = (Get-CimInstance Win32_Process -Filter "ProcessId=$pidValue").CommandLine
55+
}
56+
catch {
57+
$commandLine = ""
58+
}
5659
}
5760
return [ordered]@{
5861
pid = $pidValue
5962
commandLine = "$commandLine"
63+
cleanupPending = ($pidValue -le 0)
6064
isCurrentRepoControlPlane = ("$commandLine" -like "*$ExpectedScriptPath*")
6165
}
6266
}
6367

68+
function Wait-ControlPlanePortSettled {
69+
param(
70+
[Parameter(Mandatory = $true)][int] $Port,
71+
[Parameter(Mandatory = $true)][string] $ExpectedScriptPath,
72+
[int] $TimeoutSeconds = 20
73+
)
74+
75+
$deadline = (Get-Date).AddSeconds($TimeoutSeconds)
76+
do {
77+
$portProcess = Get-ControlPlanePortProcess -Port $Port -ExpectedScriptPath $ExpectedScriptPath
78+
if ($null -eq $portProcess) {
79+
return $null
80+
}
81+
if ($portProcess.isCurrentRepoControlPlane) {
82+
return $portProcess
83+
}
84+
if (-not $portProcess.cleanupPending) {
85+
return $portProcess
86+
}
87+
Start-Sleep -Seconds 1
88+
} while ((Get-Date) -lt $deadline)
89+
90+
return (Get-ControlPlanePortProcess -Port $Port -ExpectedScriptPath $ExpectedScriptPath)
91+
}
92+
6493
if ($LiveProfile -and $MaxBlocks -gt 0) {
6594
throw "Live service profile must not use bounded MaxBlocks mode."
6695
}
@@ -95,9 +124,12 @@ if ($controlStatus.running -and -not $controlStatus.commandLineMatched) {
95124
$controlStatus = Test-FlowChainPid -PidPath $controlPlanePidPath -CommandLineIncludes @($controlPlaneScriptPath)
96125
}
97126
if (-not ($controlStatus.running -and $controlStatus.commandLineMatched)) {
98-
$portProcess = Get-ControlPlanePortProcess -Port $ControlPlanePort -ExpectedScriptPath $controlPlaneScriptPath
127+
$portProcess = Wait-ControlPlanePortSettled -Port $ControlPlanePort -ExpectedScriptPath $controlPlaneScriptPath
99128
if ($null -ne $portProcess) {
100129
if (-not $portProcess.isCurrentRepoControlPlane) {
130+
if ($portProcess.cleanupPending) {
131+
throw "Control-plane port $ControlPlanePort is still being released by Windows. Retry service start or choose another port."
132+
}
101133
throw "Control-plane port $ControlPlanePort is already in use by a process that was not launched from this repository. Stop that process or choose another port."
102134
}
103135
Set-Content -LiteralPath $controlPlanePidPath -Value "$($portProcess.pid)"

infra/scripts/flowchain-service-status.ps1

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,14 @@ if (-not $controlPlaneReady) {
3535
$connections = @(Get-NetTCPConnection -LocalPort $ControlPlanePort -ErrorAction SilentlyContinue | Select-Object -First 1)
3636
if ($connections.Count -gt 0) {
3737
$portPid = [int]$connections[0].OwningProcess
38-
try {
39-
$commandLine = (Get-CimInstance Win32_Process -Filter "ProcessId=$portPid").CommandLine
40-
}
41-
catch {
42-
$commandLine = ""
38+
$commandLine = ""
39+
if ($portPid -gt 0) {
40+
try {
41+
$commandLine = (Get-CimInstance Win32_Process -Filter "ProcessId=$portPid").CommandLine
42+
}
43+
catch {
44+
$commandLine = ""
45+
}
4346
}
4447
if ("$commandLine" -like "*$controlPlaneScriptPath*") {
4548
$controlPlaneStatus["running"] = $true
@@ -50,6 +53,7 @@ if (-not $controlPlaneReady) {
5053
else {
5154
$controlPlanePortProcess = [ordered]@{
5255
pid = $portPid
56+
cleanupPending = ($portPid -le 0)
5357
currentRepoControlPlane = $false
5458
}
5559
}
@@ -71,7 +75,12 @@ if (-not $controlPlaneReady) {
7175
Add-FlowChainReadinessProblem -Problems $problems -Name "devnet/local/services/control-plane.pid" -Reason "control-plane process is not running from this repository" -Category "process"
7276
}
7377
if ($null -ne $controlPlanePortProcess -and -not $controlPlaneReady) {
74-
Add-FlowChainReadinessProblem -Problems $problems -Name "127.0.0.1:$ControlPlanePort" -Reason "control-plane port is occupied by a process that was not launched from this repository" -Kind "failed" -Category "process"
78+
if ($controlPlanePortProcess.cleanupPending) {
79+
Add-FlowChainReadinessProblem -Problems $problems -Name "127.0.0.1:$ControlPlanePort" -Reason "control-plane port is still being released by Windows" -Category "process"
80+
}
81+
else {
82+
Add-FlowChainReadinessProblem -Problems $problems -Name "127.0.0.1:$ControlPlanePort" -Reason "control-plane port is occupied by a process that was not launched from this repository" -Kind "failed" -Category "process"
83+
}
7584
}
7685
if (-not $stateFacts.readable) {
7786
Add-FlowChainReadinessProblem -Problems $problems -Name "devnet/local/state.json" -Reason "state file is missing or unreadable" -Category "artifact"
@@ -110,7 +119,7 @@ $report = [ordered]@{
110119
commandLineMatched = $nodeStatus.commandLineMatched
111120
}
112121
controlPlane = [ordered]@{
113-
status = if ($controlPlaneReady) { "running" } elseif ($null -ne $controlPlanePortProcess) { "port-occupied" } elseif ($controlPlaneStatus.running) { "pid-mismatch" } else { "stopped" }
122+
status = if ($controlPlaneReady) { "running" } elseif ($null -ne $controlPlanePortProcess -and $controlPlanePortProcess.cleanupPending) { "port-cleanup-pending" } elseif ($null -ne $controlPlanePortProcess) { "port-occupied" } elseif ($controlPlaneStatus.running) { "pid-mismatch" } else { "stopped" }
114123
pid = $controlPlaneStatus.pid
115124
pidPath = "devnet/local/services/control-plane.pid"
116125
commandLineMatched = $controlPlaneReady

0 commit comments

Comments
 (0)