Wait for the port thief to bind before recovering
Why: Popen returns before python http.server finishes binding, so on slower CI runners recover won the race and started the service, turning the port-stolen case into a flake. Evidence: single-case rerun OK locally; make test-governance rerun recorded on the task card; CI on the new head is authoritative. Impact: test synchronization only. Refs: .task/feature-svc-autorecover.md
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -8,8 +8,10 @@
|
||||
import fcntl
|
||||
import os
|
||||
import shutil
|
||||
import socket
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
@@ -227,10 +229,8 @@ class SvcAutoRecoverTests(unittest.TestCase):
|
||||
for _ in range(100): # 等 bash 主进程消失(HTTP 子进程由 ppid 看护自杀)
|
||||
if not self.pid_alive(pid):
|
||||
break
|
||||
import time
|
||||
time.sleep(0.05)
|
||||
self.assertFalse(self.pid_alive(pid))
|
||||
import time
|
||||
time.sleep(0.6)
|
||||
return pid
|
||||
|
||||
@@ -335,6 +335,24 @@ class SvcAutoRecoverTests(unittest.TestCase):
|
||||
["python3", "-m", "http.server", "18808", "--bind", "127.0.0.1"],
|
||||
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
self.addCleanup(thief.terminate)
|
||||
# 等 thief 真正完成 bind 再 recover——慢环境里 Popen 返回时端口尚未监听,
|
||||
# recover 会抢先起服务,把“端口被抢”测成竞态(CI 首轮实测)。
|
||||
deadline = time.monotonic() + 5.0
|
||||
bound = False
|
||||
while time.monotonic() < deadline:
|
||||
s = socket.socket()
|
||||
s.settimeout(0.2)
|
||||
try:
|
||||
s.connect(("127.0.0.1", 18808))
|
||||
bound = True
|
||||
except OSError:
|
||||
pass
|
||||
finally:
|
||||
s.close()
|
||||
if bound:
|
||||
break
|
||||
time.sleep(0.05)
|
||||
self.assertTrue(bound, "thief 未能在 5s 内监听 18808")
|
||||
try:
|
||||
result = self.svc("recover", check=False)
|
||||
self.assertEqual(result.returncode, 1, result.stdout)
|
||||
|
||||
Reference in New Issue
Block a user