fix(windows): append compute host logs without concurrent record loss
This commit is contained in:
1 parent
4115f1b4c0
commit
3f12c627ab
2 files changed
+53
-2
No files matched your search
@@ -1,6 +1,7 @@
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
@@ -118,6 +119,35 @@ def test_append_log_record_single_write_lines(tmp_path):
|
||||
assert all(line.endswith("x" * 2000) for line in lines)
|
||||
|
||||
|
||||
def test_append_log_record_across_processes_preserves_unicode(tmp_path):
|
||||
path = tmp_path / "nested" / "shared.log"
|
||||
child_code = """
|
||||
import sys, time
|
||||
from tui_gateway.host_supervisor import append_log_record
|
||||
for i in range(100):
|
||||
append_log_record(sys.argv[1], f'{sys.argv[2]}:{i}:' + '\u0130\u015f\u011f\U0001f680' * 100)
|
||||
time.sleep(0.001)
|
||||
"""
|
||||
children = [subprocess.Popen(
|
||||
[sys.executable, "-c", child_code, str(path), str(index)],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||
creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0),
|
||||
) for index in range(4)]
|
||||
try:
|
||||
for child in children:
|
||||
_, errors = child.communicate(timeout=30)
|
||||
assert child.returncode == 0, errors.decode("utf-8", errors="replace")
|
||||
finally:
|
||||
for child in children:
|
||||
if child.poll() is None:
|
||||
child.kill()
|
||||
child.communicate(timeout=10)
|
||||
lines = path.read_text(encoding="utf-8").splitlines()
|
||||
expected = {f"{process}:{index}:" + "İşğ🚀" * 100 for process in range(4) for index in range(100)}
|
||||
assert len(lines) == len(expected)
|
||||
assert set(lines) == expected
|
||||
|
||||
|
||||
def test_supervisor_startup_reconcile_pid_reuse_guard(tmp_path, monkeypatch):
|
||||
registry = tmp_path / "dashboard-compute-host.json"
|
||||
registry.write_text(json.dumps({"host_pid": os.getpid(), "boot_id": "stale"}), encoding="utf-8")
|
||||
|
||||
@@ -55,14 +55,35 @@ _LATE_CONTROL_MAX = 64
|
||||
|
||||
|
||||
def append_log_record(path: str | Path, record: str) -> None:
|
||||
"""Append one log record using O_APPEND and exactly one os.write call."""
|
||||
"""Append a record with one native write and kernel-owned EOF placement."""
|
||||
p = Path(path)
|
||||
p.parent.mkdir(parents=True, exist_ok=True)
|
||||
text = record if record.endswith("\n") else f"{record}\n"
|
||||
data = text.encode("utf-8", errors="replace")
|
||||
if sys.platform == "win32":
|
||||
import ntsecuritycon
|
||||
import win32con
|
||||
import win32file
|
||||
|
||||
# The Windows CRT's O_APPEND seeks before writing, so independent file
|
||||
# descriptors can choose the same offset. Append-only access delegates
|
||||
# EOF placement to the kernel, without granting overwrite permission.
|
||||
handle = win32file.CreateFile(
|
||||
str(p), ntsecuritycon.FILE_APPEND_DATA,
|
||||
win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE | win32con.FILE_SHARE_DELETE,
|
||||
None, win32con.OPEN_ALWAYS, win32con.FILE_ATTRIBUTE_NORMAL, None,
|
||||
)
|
||||
try:
|
||||
_, written = win32file.WriteFile(handle, data)
|
||||
if written != len(data):
|
||||
raise OSError("Incomplete log record write")
|
||||
finally:
|
||||
handle.Close()
|
||||
return
|
||||
fd = os.open(str(p), os.O_WRONLY | os.O_CREAT | os.O_APPEND, 0o600)
|
||||
try:
|
||||
os.write(fd, data)
|
||||
if os.write(fd, data) != len(data):
|
||||
raise OSError("Incomplete log record write")
|
||||
finally:
|
||||
os.close(fd)
|
||||
|
||||
|
||||
Reference in new issue
Block a user