Keep UDS post-kill cleanup best-effort
`unlink_uds_bind_addrs()` reconstructs self-assigned socket paths after a hard kill. An over-budget bindspace can make `UDSAddress.get_sockname()` raise before the guarded `os.unlink()`, replacing the original supervision outcome after the child is gone. Catch and report reconstruction failures, then skip cleanup without raising. Cover the overflow path and prove no unlink is attempted. Review: PR #480 (goodboy) https://github.com/goodboy/tractor/pull/480 (this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))wkt/uds_macos_473
parent
bd38204fde
commit
0d6d7c2a63
|
|
@ -7,6 +7,8 @@ import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import stat
|
import stat
|
||||||
import sys
|
import sys
|
||||||
|
from types import SimpleNamespace
|
||||||
|
from unittest.mock import Mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import trio
|
import trio
|
||||||
|
|
@ -234,6 +236,44 @@ def test_uds_sockname_compaction(
|
||||||
assert f'AF_UNIX path limit: {path_limit}' in errmsg
|
assert f'AF_UNIX path limit: {path_limit}' in errmsg
|
||||||
|
|
||||||
|
|
||||||
|
def test_uds_reaper_ignores_unreconstructable_path(
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
):
|
||||||
|
'''
|
||||||
|
Keep post-kill UDS cleanup best-effort on path overflow.
|
||||||
|
|
||||||
|
`unlink_uds_bind_addrs()` reconstructs a self-assigned socket from
|
||||||
|
the dead actor's name and PID. An over-budget bindspace makes that
|
||||||
|
naming helper raise before `os.unlink()`; propagating the error
|
||||||
|
would replace the original supervision outcome after the child was
|
||||||
|
already killed. This test forces overflow and proves cleanup skips
|
||||||
|
reconstruction without attempting an unlink or raising.
|
||||||
|
|
||||||
|
'''
|
||||||
|
from tractor.ipc import _uds
|
||||||
|
from tractor.spawn import _reap
|
||||||
|
|
||||||
|
long_bindspace: Path = Path('/tmp') / ('x' * 120)
|
||||||
|
proc = SimpleNamespace(pid=12345)
|
||||||
|
subactor = SimpleNamespace(
|
||||||
|
aid=SimpleNamespace(name='worker'),
|
||||||
|
)
|
||||||
|
unlink = Mock()
|
||||||
|
monkeypatch.setattr(
|
||||||
|
_uds.UDSAddress,
|
||||||
|
'def_bindspace',
|
||||||
|
long_bindspace,
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(_reap.os, 'unlink', unlink)
|
||||||
|
|
||||||
|
_reap.unlink_uds_bind_addrs(
|
||||||
|
proc=proc,
|
||||||
|
subactor=subactor,
|
||||||
|
)
|
||||||
|
|
||||||
|
unlink.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
def test_uds_bindspace_created_implicitly(
|
def test_uds_bindspace_created_implicitly(
|
||||||
debug_mode: bool,
|
debug_mode: bool,
|
||||||
bindspace_dir_str: str,
|
bindspace_dir_str: str,
|
||||||
|
|
|
||||||
|
|
@ -155,11 +155,21 @@ def unlink_uds_bind_addrs(
|
||||||
and subactor is not None
|
and subactor is not None
|
||||||
and proc.pid is not None
|
and proc.pid is not None
|
||||||
):
|
):
|
||||||
|
try:
|
||||||
sockname: Path = UDSAddress.get_sockname(
|
sockname: Path = UDSAddress.get_sockname(
|
||||||
name=subactor.aid.name,
|
name=subactor.aid.name,
|
||||||
pid=proc.pid,
|
pid=proc.pid,
|
||||||
bindspace=UDSAddress.def_bindspace,
|
bindspace=UDSAddress.def_bindspace,
|
||||||
)
|
)
|
||||||
|
except Exception:
|
||||||
|
log.exception(
|
||||||
|
f'Failed to reconstruct UDS sock-file for '
|
||||||
|
f'post-kill cleanup — skipping\n'
|
||||||
|
f' |_{proc}\n'
|
||||||
|
f' |_{subactor.aid}\n'
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
sockpath: str = str(
|
sockpath: str = str(
|
||||||
UDSAddress.def_bindspace / sockname
|
UDSAddress.def_bindspace / sockname
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue