Skip to content

Stop owned processes when their coroutine exits - #99

Merged
binaryfire merged 15 commits into
0.4from
fix/process-coroutine-cleanup
Nov 2, 2026
Merged

binaryfire merged 15 commits into
0.4from
fix/process-coroutine-cleanup

Conversation

@binaryfire

@binaryfire binaryfire commented Nov 2, 2026 •

Copy link
Copy Markdown
Member

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.


Summary by cubic

Stops asynchronous processes when the coroutine that started them exits, so orphaned native process resources are released instead of lingering until shutdown.

  • Processes started outside a coroutine, or explicitly detached with create_new_console, keep their previous lifetime and require manual wait or stop.
  • Output callback failures in MySQL/Postgres schema dumps, queue listeners, and Composer operations stop the child process before rethrowing; when that emergency cleanup also cancels, the original callback failure is preserved, including when it already wraps a cancellation.
  • Test fixtures that only need coroutine-lifetime cleanup now use the Process API; termination-timing tests keep explicit cleanup.
  • support and foundation now declare a direct dependency on symfony/process; process adds a hypervel/context dependency.

Written for commit 57e74a4. Summary will update on new commits.

View guided diff Turn on auto-fix

Note

Stop owned processes automatically when their starting coroutine exits

  • PendingProcess::start now registers the Symfony process in the current coroutine's ProcessState; ProcessState.php stops all tracked processes via a coroutine defer callback when the owner exits, including on cancellation. Processes started outside a coroutine or with create_new_console are not registered.
  • Moves GuardsProcessOutput from Hypervel\Process\Concerns to Hypervel\Support\Traits in GuardsProcessOutput.php. On an output-callback exception it attempts Process.stop(0) up to twice and picks between the callback exception and any cleanup cancellation when rethrowing.
  • Applies the guard to dump, queue worker, and Composer package-command callbacks in MySqlSchemaState, PostgresSchemaState, Listener, and Composer, so a throwing output callback stops the subprocess before the exception propagates.
  • Updates process, testing, and porting docs to describe coroutine ownership, pool cleanup, and explicit stop guidance; many tests add finally cleanup or switch to the Hypervel process API.
  • Behavioral Change: installing the foundation and support packages now requires symfony/process ^8.1, and the process package requires hypervel/context ^0.4 (composer.json, composer.json). Existing consumers importing GuardsProcessOutput from Hypervel\Process\Concerns must update to the new namespace.

Macroscope summarized 57e74a4.

Summary by CodeRabbit

  • New Features
    • Asynchronous processes and process pools are now stopped automatically when their owning coroutine exits, including when it is canceled. Detached processes remain independent of coroutine cleanup.
    • Output-handler failures now trigger process cleanup before the original error is surfaced.
  • Documentation
    • Clarified process ownership, cancellation, detachment, and cleanup guidance for asynchronous processes, pools, testing, and Laravel migrations.

Track native process handles weakly in coroutine-local state and reuse pool cleanup at owner exit. Preserve detached, fake and non-coroutine starts. Share the output guard through Support while retaining interrupted-stop behavior.

Verified ProcessTest, ProcessNonCoroutineTest, real concurrency consumers, source/type analysis and facade consistency.
Guard require and remove output callbacks so their exceptions cannot leave Composer changing the project in the background.

Both real-child regressions fail before correction; SupportComposerTest passes.
Apply the shared output guard to MySQL, MariaDB and PostgreSQL dump callbacks without changing schema extension points.

Real-child regressions fail before correction; MySQL and PostgreSQL schema-state test files pass.
Prevent a caller-supplied output handler from abandoning the current worker process after an exception.

The regression fails before correction; QueueListenerTest passes.
Declare the Process component used directly by Foundation console commands and Composer integration, using the framework's existing version constraint.

Package metadata parses successfully; no root dependency versions change.
Start the fixture through the Process API while retaining graceful shutdown before log inspection.

SwooleMaintenanceTimerWorkerRecycleTest passes.
Use coroutine-owned subprocesses and return ProcessResult from the profiler helper, preserving output, exit-code and report-cleanup assertions.

ProfileScriptTest passes.
Retain each child before starting it and stop all started readers if startup, waiting or an assertion fails.

FilesystemNonCoroutineTest passes.
Avoid signaling the test runner's process group when the fixture has no process ID.

HttpClientStreamingTest passes with its established platform skip.
Keep real workers and supervisor processes inside exception-safe cleanup while preserving mocked behavior and assertions.

Both changed Horizon files pass against an isolated temporary Redis instance.
Keep process-group cleanup limited to a fixture with a known process ID.

ShutdownOnInterruptListenerTest passes with its established Swoole skips.
Guard nullable process IDs and remove the startup sleep because Symfony obtains the PID during start.

CommanderServeTest passes directly and through package:test with one worker.
Explain coroutine-exit cleanup, explicit detachment and raw Symfony ownership. Recommend the framework Process API for fixtures while retaining explicit shutdown where timing or process trees require it.

Documentation matches the reviewed source and behavior tests.
Integrate the merged framework and integration cancellation fixes before publishing process ownership and callback cleanup. Preserve cancellation-aware stop, pool cleanup and regression coverage alongside the previously reviewed weak process tracking and shared output guard.

The merge needs no conflict resolution. The process change remains 31 files; differences from its reviewed patch only reflect already-landed dependencies, imports and adjacent cancellation changes. Complete Process and non-coroutine tests, targeted source analysis and formatting pass.
@coderabbitai

coderabbitai Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between ae4f012 and d4084e1.

Files selected for processing: 31
  • src/database/src/Schema/MySqlSchemaState.php
  • src/database/src/Schema/PostgresSchemaState.php
  • src/database/src/Schema/SchemaState.php
  • src/docs/porting-from-laravel.md
  • src/docs/processes.md
  • src/docs/testing.md
  • src/foundation/composer.json
  • src/process/README.md
  • src/process/composer.json
  • src/process/src/InvokedProcess.php
  • src/process/src/PendingProcess.php
  • src/process/src/Pool.php
  • src/process/src/ProcessState.php
  • src/queue/src/Listener.php
  • src/support/composer.json
  • src/support/src/Composer.php
  • src/support/src/Traits/GuardsProcessOutput.php
  • tests/Cache/SwooleMaintenanceTimerWorkerRecycleTest.php
  • tests/Database/DatabaseMySqlSchemaStateTest.php
  • tests/Database/DatabasePostgresSchemaStateTest.php
  • tests/Filesystem/FilesystemNonCoroutineTest.php
  • tests/Http/HttpClientStreamingTest.php
  • tests/Integration/Horizon/Feature/AddSupervisorTest.php
  • tests/Integration/Horizon/Feature/WorkerProcessTest.php
  • tests/Process/ProcessNonCoroutineTest.php
  • tests/Process/ProcessTest.php
  • tests/Queue/QueueListenerTest.php
  • tests/Server/Listeners/ShutdownOnInterruptListenerTest.php
  • tests/Support/SupportComposerTest.php
  • tests/Testbench/CommanderServeTest.php
  • tests/Testing/Profile/ProfileScriptTest.php

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Walkthrough

The change adds coroutine-scoped process ownership and updates output-callback failure handling to stop affected processes. It also updates process guidance, adopts Hypervel process APIs in tests, and adds subprocess cleanup to test cases.

Changes: Process lifecycle and output handling

Layer / File(s) Summary
Coroutine-owned process lifecycle
src/process/src/ProcessState.php, src/process/src/PendingProcess.php, src/process/src/Pool.php, src/process/composer.json, tests/Process/*, src/docs/processes.md, src/docs/porting-from-laravel.md, src/docs/testing.md, src/process/README.md
PendingProcess::start() registers attached processes with coroutine state. ProcessState stops tracked processes on coroutine exit. Documentation describes ownership, detachment, and cleanup. Tests cover cancellation, completed processes, forked coroutines, and non-coroutine use.
Output callback failure cleanup
src/support/src/Traits/GuardsProcessOutput.php, src/support/src/Composer.php, src/database/src/Schema/*, src/queue/src/Listener.php, src/support/composer.json, src/foundation/composer.json, tests/Database/*, tests/Queue/QueueListenerTest.php, tests/Support/SupportComposerTest.php, tests/Process/ProcessTest.php
The shared guard stops processes after output callback failures and preserves exception handling. Database dump, queue worker, and Composer process paths use the guard. Tests verify that callback exceptions propagate and the processes stop.
Hypervel process APIs in tests
tests/Cache/SwooleMaintenanceTimerWorkerRecycleTest.php, tests/Testing/Profile/ProfileScriptTest.php
The tests use Hypervel process APIs instead of Symfony Process directly. Profiler tests read output and exit status from ProcessResult.
Subprocess test cleanup
tests/Filesystem/FilesystemNonCoroutineTest.php, tests/Integration/Horizon/Feature/*, tests/Http/HttpClientStreamingTest.php, tests/Server/Listeners/ShutdownOnInterruptListenerTest.php, tests/Testbench/CommanderServeTest.php
Tests stop subprocesses in cleanup blocks and skip process-group signals when the PID is null. The serve test also removes a delay before recording the process PID.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant PendingProcess
  participant SymfonyProcess
  participant ProcessState
  participant InvokedProcessPool
  PendingProcess->>SymfonyProcess: Start process
  PendingProcess->>ProcessState: Register attached process
  ProcessState->>InvokedProcessPool: Stop tracked processes on coroutine exit
Loading
Merge Risk: Low · previous review d4084

A process may remain running after an output callback fails if cleanup also fails. This narrow failure path warrants a fix or explicit acceptance before merging.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 38.71% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documenta… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title "Stop owned processes when their coroutine exits" matches the main change. The PR tracks asynchronous processes per coroutine in ProcessState and stops them when the owning coroutine exits, …
Description check Passed The description follows the template's main sections: Problem and change, Supporting evidence, Verification, and the checklist. It explains the problem (asynchronous processes left running after their…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

The title "Stop owned processes when their coroutine exits" matches the main change. The PR tracks asynchronous processes per coroutine in ProcessState and stops them when the owning coroutine exits, as the raw summary and PR objectives describe. The title omits the output-failure guard move and the docs/test changes, which is acceptable because the title need not cover every detail.

Full details: Description check

Explanation

The description follows the template's main sections: Problem and change, Supporting evidence, Verification, and the checklist. It explains the problem (asynchronous processes left running after their coroutine exits, and output callback failures interrupting cleanup), the change, and the detachment and non-coroutine exceptions. Gaps: the contribution type checkboxes are not selected, the Supporting evidence section does not give the regression test with failing and passing results for the bug fix, and the Verification section does not list the composer fix run from the repository root. It also states that the full suite runs in CI, which does not satisfy the required pre-PR composer fix run. The description is mostly complete, so the check passes, but the author should fill these gaps.

Full details: Docstring Coverage

Explanation

Docstring coverage is 38.71% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 31 functions across 24 files. (7 skipped: 7 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches
Generate docstrings
  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@binaryfire

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Stop owned processes when their coroutine exits

🐞 Bug fix 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

AI Description

• Stop asynchronous processes left running when their owning coroutine exits, including on
 cancellation.
• Stop schema, queue, and Composer children when output callbacks fail.
• Add lifecycle regressions and document ownership, detachment, and subprocess fixture guidance.
Diagram

graph TD
  Owner["Owning coroutine"] --> Starter["Pending process"] --> Child["Symfony child"]
  Starter --> State["Coroutine state"] --> Cleanup["Exit cleanup"] --> PoolStop["Pool stop"] --> Child
  Starter --> Guard["Output guard"] --> Child
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Strong registry with explicit deregistration
  • ➕ Would retain a process for cleanup even after callers discard its handle.
  • ➖ Would need reliable deregistration on every completion and failure path.
  • ➖ Could retain completed process resources throughout a long-lived coroutine.

Recommendation: Keep the weak coroutine-local registry and reuse pool cleanup: it adds owner-exit protection without retaining completed processes or copying ownership into forked coroutines. The strong-registry alternative adds lifecycle bookkeeping and retention risk.

Files changed (31) +464 / -119

Bug fix (8) +121 / -30
MySqlSchemaState.phpGuard MySQL dump output +1/-1

Guard MySQL dump output

• Wraps dump output callbacks so a callback failure stops the active process before propagating.

src/database/src/Schema/MySqlSchemaState.php

PostgresSchemaState.phpGuard PostgreSQL dump output +3/-1

Guard PostgreSQL dump output

• Retains the created process while wrapping its dump output callback for failure cleanup.

src/database/src/Schema/PostgresSchemaState.php

SchemaState.phpShare process output protection with schema states +3/-0

Share process output protection with schema states

• Adds the Support output-guard trait to the schema-state base class.

src/database/src/Schema/SchemaState.php

PendingProcess.phpRegister eligible asynchronous children with their owner +10/-3

Register eligible asynchronous children with their owner

• Tracks successfully started, non-detached real processes when running in a coroutine. Updates the start contract to describe automatic owner-exit cleanup.

src/process/src/PendingProcess.php

ProcessState.phpAdd coroutine-local weak process ownership +61/-0

Add coroutine-local weak process ownership

• Stores process instances in a non-copyable WeakMap and registers one deferred cleanup per owning coroutine. Cleanup reuses the invoked-process pool's stop behavior.

src/process/src/ProcessState.php

Listener.phpStop queue workers after output-handler failures +5/-2

Stop queue workers after output-handler failures

• Wraps the listener's worker output callback with the shared guard.

src/queue/src/Listener.php

Composer.phpGuard Composer command output callbacks +21/-14

Guard Composer command output callbacks

• Protects both package require and remove operations so output failures stop their child processes.

src/support/src/Composer.php

GuardsProcessOutput.phpMove and generalize process output cleanup guard +17/-9

Move and generalize process output cleanup guard

• Relocates the guard to Support for direct Symfony Process callers. It retries an interrupted stop and preserves callback failure or cancellation behavior.

src/support/src/Traits/GuardsProcessOutput.php

Refactor (1) +1 / -1
InvokedProcess.phpUse the shared Support output guard +1/-1

Use the shared Support output guard

• Switches invoked processes to the relocated output-guard trait without changing their public API.

src/process/src/InvokedProcess.php

Tests (14) +323 / -85
SwooleMaintenanceTimerWorkerRecycleTest.phpRun cache timer server through the Process API +9/-8

Run cache timer server through the Process API

• Moves the server fixture to ProcessFactory and adapts result access while retaining an explicit stop before log inspection.

tests/Cache/SwooleMaintenanceTimerWorkerRecycleTest.php

DatabaseMySqlSchemaStateTest.phpRegress MySQL dump callback cleanup +28/-0

Regress MySQL dump callback cleanup

• Checks that a real child stops and the original exception survives a failing dump output callback.

tests/Database/DatabaseMySqlSchemaStateTest.php

DatabasePostgresSchemaStateTest.phpRegress PostgreSQL dump callback cleanup +28/-0

Regress PostgreSQL dump callback cleanup

• Checks that a failing dump output handler stops the real child and propagates its exception.

tests/Database/DatabasePostgresSchemaStateTest.php

FilesystemNonCoroutineTest.phpClean up direct Symfony fixtures on failure +18/-12

Clean up direct Symfony fixtures on failure

• Places concurrent subprocess creation and waiting inside a try/finally that stops every started process.

tests/Filesystem/FilesystemNonCoroutineTest.php

HttpClientStreamingTest.phpGuard streaming fixture process-group cleanup +3/-1

Guard streaming fixture process-group cleanup

• Avoids signaling a process group when its PID was not obtained.

tests/Http/HttpClientStreamingTest.php

AddSupervisorTest.phpAlways stop the Horizon supervisor fixture +13/-11

Always stop the Horizon supervisor fixture

• Moves supervisor cleanup into finally so failed assertions cannot leave it running.

tests/Integration/Horizon/Feature/AddSupervisorTest.php

WorkerProcessTest.phpAlways kill Horizon worker fixtures +15/-7

Always kill Horizon worker fixtures

• Adds termination in finally blocks across worker lifecycle and signal regressions.

tests/Integration/Horizon/Feature/WorkerProcessTest.php

ProcessNonCoroutineTest.phpCover asynchronous starts outside coroutines +24/-0

Cover asynchronous starts outside coroutines

• Verifies that a ProcessFactory child can start and finish without coroutine ownership, with explicit fixture cleanup.

tests/Process/ProcessNonCoroutineTest.php

ProcessTest.phpCover coroutine ownership and weak cleanup +89/-7

Cover coroutine ownership and weak cleanup

• Tests owner return, cancellation, detachment, completed-process release, and non-inheritance by forked coroutines. Updates output-guard expectations and removes a pool wait no longer needed solely for cleanup.

tests/Process/ProcessTest.php

QueueListenerTest.phpRegress queue listener output-failure cleanup +23/-0

Regress queue listener output-failure cleanup

• Verifies that a throwing output handler stops a real worker child and preserves the exception.

tests/Queue/QueueListenerTest.php

ShutdownOnInterruptListenerTest.phpGuard shutdown fixture process-group cleanup +9/-3

Guard shutdown fixture process-group cleanup

• Signals fixture process groups only when their PIDs are available, while retaining explicit process stops.

tests/Server/Listeners/ShutdownOnInterruptListenerTest.php

SupportComposerTest.phpRegress Composer callback failure cleanup +30/-0

Regress Composer callback failure cleanup

• Checks both require and remove operations against real children whose output callbacks throw.

tests/Support/SupportComposerTest.php

CommanderServeTest.phpHarden serve fixture shutdown +6/-5

Harden serve fixture shutdown

• Guards process-group signals when no PID is available and removes an unnecessary post-start delay.

tests/Testbench/CommanderServeTest.php

ProfileScriptTest.phpRun profiler fixtures through the Process API +28/-31

Run profiler fixtures through the Process API

• Replaces direct Symfony subprocess handling with ProcessFactory and ProcessResult while preserving exit-code and output assertions.

tests/Testing/Profile/ProfileScriptTest.php

Documentation (5) +16 / -3
porting-from-laravel.mdExplain coroutine subprocess ownership when porting +2/-0

Explain coroutine subprocess ownership when porting

• Advises starting framework processes in the coroutine that waits for them and explicitly cleaning up direct Symfony processes.

src/docs/porting-from-laravel.md

processes.mdDocument automatic owner-exit cleanup +4/-2

Document automatic owner-exit cleanup

• Explains coroutine ownership for asynchronous processes and pools, including cancellation, detachment, and non-coroutine starts.

src/docs/processes.md

testing.mdDocument subprocess fixture choices +2/-0

Document subprocess fixture choices

• Recommends the framework Process API for coroutine-owned fixtures while retaining explicit cleanup for direct Symfony or non-coroutine starts.

src/docs/testing.md

README.mdDescribe Hypervel's asynchronous process lifetime +6/-0

Describe Hypervel's asynchronous process lifetime

• Links the process documentation and calls out owner-exit cleanup as a difference from Laravel.

src/process/README.md

Pool.phpClarify pool owner-exit behavior +2/-1

Clarify pool owner-exit behavior

• Updates the start documentation to state that owned pool children are stopped at coroutine exit unless detached.

src/process/src/Pool.php

Other (3) +3 / -0
composer.jsonDeclare Foundation's Symfony Process dependency +1/-0

Declare Foundation's Symfony Process dependency

• Adds the Symfony Process component used directly by Foundation.

src/foundation/composer.json

composer.jsonDeclare Process's coroutine-context dependency +1/-0

Declare Process's coroutine-context dependency

• Adds the Context package required for coroutine-local process tracking.

src/process/composer.json

composer.jsonDeclare Support's Symfony Process dependency +1/-0

Declare Support's Symfony Process dependency

• Adds the dependency required by the shared process output guard.

src/support/composer.json

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Discarded handles leave children running 🐞 Bug ☼ Reliability
Description
ProcessState stores each started Symfony process only as a weak key, so discarding the returned
InvokedProcess can remove the process from the ownership map before coroutine exit. When the
deferred stop() runs, it iterates only surviving keys and cannot stop that child; the new
lifecycle test does not cover this case because it retains the underlying Symfony process
separately.
Code

src/process/src/ProcessState.php[R22-23]

+    /** @var WeakMap<Process, true> */
+    public WeakMap $processes;
Evidence
start() registers the process under a weak key, while exit cleanup can stop only keys still in
that map. The test explicitly extracts and retains the Symfony process after discarding its facade,
keeping the weak key alive throughout the assertion.

src/process/src/PendingProcess.php[265-271]
src/process/src/ProcessState.php[22-23]
src/process/src/ProcessState.php[51-59]
tests/Process/ProcessTest.php[99-104]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The weak ownership map loses a running process when its returned handle is discarded, leaving coroutine-exit cleanup unable to stop it.
## Fix Focus Areas
- src/process/src/ProcessState.php[22-59]
- src/process/src/PendingProcess.php[265-271]
- tests/Process/ProcessTest.php[92-145]
## Recommended Fix
Keep a strong reference to each running owned process until it is stopped or completed, then remove it so completed processes do not accumulate. Add a regression that discards the returned handle without retaining the underlying Symfony process and verifies the child is stopped when its coroutine exits.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can copy the agent prompt from any finding and feed it to your IDE agent

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@binaryfire

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Fix comments: Fix CodeRabbit comments on this PR

A callback failure can already carry cancellation in its exception chain. If emergency stop also throws cancellation, checking only the callback exception class replaces that original failure and loses its cleanup context.

Use the shared cancellation-precedence helper when selecting the callback or stop failure. Keep the native-only stop catch, bounded retry and callback re-entry guard unchanged.

Extend the existing emergency-stop regression with a wrapped callback failure and assert the retained exception identity. The added row fails before the correction; the complete Process test file, targeted analysis of the trait and its consumers, and formatting pass.
@binaryfire

Copy link
Copy Markdown
Member Author

The weak-ownership finding is declined. An attached Symfony Process stops its child in __destruct(), so leaving the WeakMap through destruction does not abandon the child. Quiet processes without a retaining callback can be destroyed immediately; output-enabled processes can remain reachable through their callback until owner cleanup. A real probe discarding the facade handle while retaining only its PID confirms that the child is gone after owner exit. Strong references and explicit deregistration would add retention and bookkeeping without fixing a reproduced failure.

@binaryfire
binaryfire merged commit 7034f76 into 0.4 Nov 2, 2026
46 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant