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
Gud Boi 2026-08-13 18:57:13 -04:00
parent bd38204fde
commit 0d6d7c2a63
2 changed files with 55 additions and 5 deletions

View File

@ -7,6 +7,8 @@ import os
from pathlib import Path
import stat
import sys
from types import SimpleNamespace
from unittest.mock import Mock
import pytest
import trio
@ -234,6 +236,44 @@ def test_uds_sockname_compaction(
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(
debug_mode: bool,
bindspace_dir_str: str,

View File

@ -155,11 +155,21 @@ def unlink_uds_bind_addrs(
and subactor is not None
and proc.pid is not None
):
sockname: Path = UDSAddress.get_sockname(
name=subactor.aid.name,
pid=proc.pid,
bindspace=UDSAddress.def_bindspace,
)
try:
sockname: Path = UDSAddress.get_sockname(
name=subactor.aid.name,
pid=proc.pid,
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(
UDSAddress.def_bindspace / sockname
)