Add `--uds`/`--uds-only` flags to `tractor-reap`
Wire up `find_orphaned_uds()` + `reap_uds()` from `_reap` as a new phase-3 UDS sweep in the CLI script. Opt-in via `--uds` (run after proc reap + shm) or `--uds-only` (skip other phases). Also, - consolidate skip-proc-reap logic into a single `skip_proc_reap` bool covering both `--shm-only` and `--uds-only` - extend header docstring + usage examples (this commit msg was generated in some part by [`claude-code`][claude-code-gh]) [claude-code-gh]: https://github.com/anthropics/claude-codesubint_forkserver_backend
parent
1cdc7fb302
commit
0996a83655
|
|
@ -23,6 +23,14 @@ Two cleanup phases (run in order when both are enabled):
|
||||||
hard-crashing actor leaves leaked segments that
|
hard-crashing actor leaves leaked segments that
|
||||||
nothing else GCs.
|
nothing else GCs.
|
||||||
|
|
||||||
|
3. **UDS sweep** (`--uds` / `--uds-only`) — unlinks
|
||||||
|
`${XDG_RUNTIME_DIR}/tractor/<name>@<pid>.sock` files
|
||||||
|
whose binder pid is dead (or the `1616` registry
|
||||||
|
sentinel). Needed because the IPC server's
|
||||||
|
`os.unlink()` cleanup lives in a `finally:` block
|
||||||
|
that doesn't always run on hard exits (SIGKILL,
|
||||||
|
escaped `KeyboardInterrupt`, etc.) — see issue #452.
|
||||||
|
|
||||||
Process-reap detection modes (auto-selected):
|
Process-reap detection modes (auto-selected):
|
||||||
|
|
||||||
--parent <pid> : descendant-mode — kill procs whose
|
--parent <pid> : descendant-mode — kill procs whose
|
||||||
|
|
@ -50,12 +58,18 @@ Usage:
|
||||||
# only the shm sweep, skip process reap
|
# only the shm sweep, skip process reap
|
||||||
scripts/tractor-reap --shm-only
|
scripts/tractor-reap --shm-only
|
||||||
|
|
||||||
|
# process reap + shm + UDS sweep (the works)
|
||||||
|
scripts/tractor-reap --shm --uds
|
||||||
|
|
||||||
|
# only UDS sweep
|
||||||
|
scripts/tractor-reap --uds-only
|
||||||
|
|
||||||
# from inside a still-live supervisor
|
# from inside a still-live supervisor
|
||||||
scripts/tractor-reap --parent 12345
|
scripts/tractor-reap --parent 12345
|
||||||
|
|
||||||
# dry-run: list what would be reaped, don't act
|
# dry-run: list what would be reaped, don't act
|
||||||
scripts/tractor-reap -n
|
scripts/tractor-reap -n
|
||||||
scripts/tractor-reap --shm -n
|
scripts/tractor-reap --shm --uds -n
|
||||||
|
|
||||||
'''
|
'''
|
||||||
import argparse
|
import argparse
|
||||||
|
|
@ -118,7 +132,28 @@ def main() -> int:
|
||||||
action='store_true',
|
action='store_true',
|
||||||
help='skip process reap; only do the shm sweep',
|
help='skip process reap; only do the shm sweep',
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--uds',
|
||||||
|
action='store_true',
|
||||||
|
help=(
|
||||||
|
'after process reap, also unlink orphaned '
|
||||||
|
'${XDG_RUNTIME_DIR}/tractor/*.sock files '
|
||||||
|
'whose binder pid is dead (or the 1616 '
|
||||||
|
'registry sentinel). See issue #452.'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--uds-only',
|
||||||
|
action='store_true',
|
||||||
|
help='skip process reap + shm; only do the UDS sweep',
|
||||||
|
)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
# any *-only flag also skips the process reap phase
|
||||||
|
skip_proc_reap: bool = (
|
||||||
|
args.shm_only
|
||||||
|
or
|
||||||
|
args.uds_only
|
||||||
|
)
|
||||||
|
|
||||||
# import lazily so `--help` doesn't require the tractor
|
# import lazily so `--help` doesn't require the tractor
|
||||||
# package to be importable (e.g. when running from a
|
# package to be importable (e.g. when running from a
|
||||||
|
|
@ -129,14 +164,16 @@ def main() -> int:
|
||||||
find_descendants,
|
find_descendants,
|
||||||
find_orphans,
|
find_orphans,
|
||||||
find_orphaned_shm,
|
find_orphaned_shm,
|
||||||
|
find_orphaned_uds,
|
||||||
reap,
|
reap,
|
||||||
reap_shm,
|
reap_shm,
|
||||||
|
reap_uds,
|
||||||
)
|
)
|
||||||
|
|
||||||
rc: int = 0
|
rc: int = 0
|
||||||
|
|
||||||
# --- phase 1: process reap (skipped under --shm-only) ---
|
# --- phase 1: process reap (skipped under --*-only) ---
|
||||||
if not args.shm_only:
|
if not skip_proc_reap:
|
||||||
if args.parent is not None:
|
if args.parent is not None:
|
||||||
pids: list[int] = find_descendants(args.parent)
|
pids: list[int] = find_descendants(args.parent)
|
||||||
mode: str = f'descendants of PPid={args.parent}'
|
mode: str = f'descendants of PPid={args.parent}'
|
||||||
|
|
@ -173,6 +210,24 @@ def main() -> int:
|
||||||
if errors:
|
if errors:
|
||||||
rc = 1
|
rc = 1
|
||||||
|
|
||||||
|
# --- phase 3: UDS sweep (opt-in) ---
|
||||||
|
if args.uds or args.uds_only:
|
||||||
|
leaked_uds: list[str] = find_orphaned_uds()
|
||||||
|
if not leaked_uds:
|
||||||
|
print(
|
||||||
|
'[tractor-reap] no orphaned UDS sock-files '
|
||||||
|
'to sweep'
|
||||||
|
)
|
||||||
|
elif args.dry_run:
|
||||||
|
print(
|
||||||
|
f'[tractor-reap] dry-run — {len(leaked_uds)} '
|
||||||
|
f'orphaned UDS sock-file(s):\n {leaked_uds}'
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
_, errors = reap_uds(leaked_uds)
|
||||||
|
if errors:
|
||||||
|
rc = 1
|
||||||
|
|
||||||
# exit 0 if everything cleaned cleanly, else 1 — useful
|
# exit 0 if everything cleaned cleanly, else 1 — useful
|
||||||
# for CI health-check chaining.
|
# for CI health-check chaining.
|
||||||
return rc
|
return rc
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue