The first repair is architectural.Do not tune persistence or worker pools around a synchronous child. DSH tool work must forward `exec.signal` and settle after every owned process and pipe reaches quiescence.

What blocks with the event loop.

Cancellation

The handler cannot run while the synchronous child owns the thread.

Timeout

A wrapper cannot settle a body whose same-process call is blocked.

Persistence

Session write completions and microtask continuations stop progressing.

Control plane

Health checks, Web RPC, and unrelated Sessions become unresponsive.

Choose the asynchronous owner.

Bounded outputexecFile(binary, argv)

No shell by default; forward the signal and set a deliberate maxBuffer.

Streaming outputspawn(binary, argv)

Consume every pipe and wait for close before returning.

Descendant treesDSH subprocess seam

Use tree-scoped termination, bounded collection, spill, and quiescent wait.

Async `exec(commandString)` is not the complete fix.

It removes event-loop blocking but keeps shell injection. Separate the executable from its argument array and never interpolate untrusted input.

Primary evidence.

Migrate the lifetime, then prove it.

The complete guide includes an execFile migration, process-tree guidance, signal and timeout ownership, shell safety, reproduction evidence, and twelve acceptance gates.

Read the complete guide