Stop owned processes when their coroutine exits
Asynchronous processes left behind by their starting coroutine could retain native process resources until shutdown. Output callback failures could also interrupt cleanup in framework callers using Symfony Process directly.
Track asynchronous processes weakly in their owning coroutine and stop any remaining children when that coroutine exits. Explicitly detached processes remain detached, and processes started outside a coroutine retain their existing lifetime.
Share the output-failure cleanup guard with schema commands, queue listeners and Composer operations. Move suitable test fixtures onto the Process API, retain independent cleanup in termination regressions, and document when tests should use the framework API or Symfony Process directly.
Targeted tests cover coroutine exit, cancellation, callback failures, process pools and non-coroutine execution. Source analysis and affected tests pass; the full suite and service matrices run in CI.
[!NOTE]
Stop owned processes when their coroutine exits
- Adds a coroutine process registry in ProcessState.php: processes started in a coroutine are tracked in a WeakMap and stopped when that coroutine exits (returns or is canceled). Detached processes via
create_new_console and starts outside a coroutine are not tracked.
- PendingProcess.start registers each async process with the current coroutine; pools inherit the same ownership.
- Moves
GuardsProcessOutput to support/src/Traits and applies it to schema dumps, queue worker listeners, and Composer package operations so a throwing output callback stops the subprocess first.
- Documents coroutine ownership in processes.md, porting-from-laravel.md, and testing.md. Updates many tests to use the Hypervel process factory and clean up in
finally.
- Risk: processes that previously kept running after a coroutine exited are now stopped automatically — check
PendingProcess.start registration and any callers relying on processes outliving their starting coroutine.
Macroscope summarized 57e74a4.
Summary by CodeRabbit
- New Features
- Asynchronous processes started within a coroutine now stop automatically when that coroutine exits, including when it is canceled. Detached processes are not stopped automatically.
- Process pools follow the same lifecycle behavior as their owning coroutine.
- Bug Fixes
- Processes are now stopped when output-handling callbacks fail, while the original error is preserved.
- Documentation
- Clarified process ownership, detachment, and cleanup guidance for asynchronous processes and test fixtures.