workspaceResidents function

Future<List<int>> workspaceResidents(
  1. String workspacePath, {
  2. required int selfPid,
  3. required Future<ProcessResult> runProcess(
    1. String,
    2. List<String>
    ),
})

Every process still WORKING somewhere under workspacePath, by current directory.

bd forks detached children that outlive the command that spawned them — bd send-metrics is the one measured here, born after a test body finished and alive for ~25 seconds afterwards. They carry no --config or --root, so workspaceStoreProcesses cannot see them, and they inherit the workspace as their working directory, which is the only mark they leave in the process table.

They are why a SIGKILL fence can run its full bound and still find a proxy: a live bd client re-spawns one to serve itself every time the fence kills the last. Killing them is also what stops a straggler from writing the store back into existence AFTER a delete that already reported success.

lsof is the only account of a working directory on this platform. If it is absent or refuses, this degrades to the store census alone — the behaviour that shipped before — and a bounded delete absorbs the difference. runProcess and selfPid are injected so both that degradation and the parse are provable without a store to point them at.

Implementation

Future<List<int>> workspaceResidents(
  String workspacePath, {
  required int selfPid,
  required Future<ProcessResult> Function(String, List<String>) runProcess,
}) async {
  final ProcessResult result;
  try {
    result = await runProcess('lsof', [
      '-w',
      '-a',
      '-d',
      'cwd',
      '-Fp',
      '+D',
      workspacePath,
    ]);
  } on ProcessException {
    return const [];
  }
  return parseLsofPids(result.stdout as String, selfPid: selfPid);
}