Skip to content

fix(python): drain requests after repeated cancellation - #25411

Open
BlueRaddish wants to merge 8 commits into
manaflow-ai:mainfrom
BlueRaddish:fix/oct26a-python-cancel-drain
Open

BlueRaddish wants to merge 8 commits into
manaflow-ai:mainfrom
BlueRaddish:fix/oct26a-python-cancel-drain

Conversation

@BlueRaddish

@BlueRaddish BlueRaddish commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Calling cancel() again while an async Python SDK request is still acknowledging its first cancellation can let the caller finish before its request worker has drained. Reuse the existing _await_cleanup helper so repeated cancellation still waits for that worker, then raises CancelledError. The regression uses client.session(...).terminal(...).wait() over a real local Unix socket, holds the cancellation acknowledgment, and confirms the same client can still ping afterward.

Testing

The focused regression fails on the rebased test-only commit dcfb31e186c700effcef0d73872adaccbc255d6a with request worker was not drained, and passes on head 01c92e9330400f97f7b168ce07798ae10a3b80b5. From cmux-tui/bindings/python/tests, the same command executes one test with no skips:

PYTHONPATH=.. python3 -m unittest test_resource_api.ResourceApiTests.test_aio_repeated_cancellation_drains_request_before_returning

Observed / Not run

  • The full Python SDK suite passed 119 tests, zero skips on Python 3.9 in the current-head CI package job, including the regression and package-install test. The audit also passed all 119 tests locally on Python 3.13.3 using an isolated environment with the declared build prerequisite installed (setuptools>=77). Command: PYTHONPATH=cmux-tui/bindings/python python3 -m unittest discover -v -s cmux-tui/bindings/python/tests.
  • Hosted Fast static checks passed all 16 checks on this head. Its project-normalizer suite has one existing platform skip; the local project-normalizer suite ran all 16 tests without skips. A separate local preflight with a 45-second command budget passed 12 checks and interrupted four unrelated checks; the full hosted recipe completed them. No test timeout or assertion was changed.
  • Rebased onto main at 36540f6194b746d48d47aa8963adbd0f1cd35cdb without conflicts. The published ancestry is retained for a plain push. git diff --check passes; the diff remains the two Python files.
  • No native app build, signing run, physical-device check, or live app check was performed for this Python SDK change. The regression exercises a disposable local Unix socket. Native app, CLI, packaging configuration, and signing files are unchanged.

Changelog

Fixed: Python async request cancellation waits for cleanup even when the caller is cancelled repeatedly.

AI-assisted with OpenAI Codex.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of repeated cancellation during terminal waits, ensuring cleanup finishes before cancellation completes.
    • Added regression coverage for cancellation acknowledgment and subsequent client responsiveness.

@cursor

cursor Bot commented Oct 26, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

@coderabbitai

coderabbitai Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between c0a0058 and 2b1fad5.

Files selected for processing: 2
  • cmux-tui/bindings/python/cmux/aio.py
  • cmux-tui/bindings/python/tests/test_resource_api.py

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

Walkthrough

Client._run_control now drains its worker future through repeated caller cancellation. A regression test checks that the task waits for the cancel acknowledgment, raises asyncio.CancelledError, and allows a subsequent ping.

Changes: Python control cancellation

Layer / File(s) Summary
Drain cancelled control requests
cmux-tui/bindings/python/cmux/aio.py, cmux-tui/bindings/python/tests/test_resource_api.py
Client._run_control uses _await_cleanup to drain the worker future after cancellation. The regression test checks repeated cancellation, cancel acknowledgment, and a subsequent successful ping.

Priority: Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Suggested reviewers: lawrencecchen

Merge Risk: Minimal · up to 2b1fa

The repeated-cancellation path has a regression test, and no remaining issue was identified that should block merging.

Pre-merge checks: Passed 24
Check name Status Explanation
Title check Passed The title "fix(python): drain requests after repeated cancellation" names the main change: the Python SDK async client now waits for its request worker to drain when the caller cancels repeatedly. It …
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.
Cmux Cloud Persistent Session And Early Input Passed PASS: The diff changes only Python request cancellation cleanup and adds a local Unix-socket regression test. It does not change Cloud terminal creation, persistent transport, renderer admission, inpu…
Cmux Swift Actor Isolation Passed The pull request changes only two Python files: cmux-tui/bindings/python/cmux/aio.py and cmux-tui/bindings/python/tests/test_resource_api.py. The reviewed diff contains no Swift files, so it does …
Cmux Swift Blocking Runtime Passed PASS: The pull request changes only Python files: cmux-tui/bindings/python/cmux/aio.py and cmux-tui/bindings/python/tests/test_resource_api.py. It introduces no production Swift changes. The test-…
Cmux Browser Automation Off-Main Passed PASS: The pull request changes only Python async request cleanup and its regression test. The diff introduces no browser socket commands, WebKit/AppKit access, main-actor routing, worker-lane routing,…
Cmux Expensive Synchronous Load Passed PASS. The pull request changes only Python files: cmux-tui/bindings/python/cmux/aio.py and its Python regression test. It adds no production Swift code or synchronous agent-history load.
Cmux Cache Substitution Correctness Passed PASS: The reviewed diff changes only Python files (cmux-tui/bindings/python/cmux/aio.py and its Python test). The cache-substitution condition applies only to production Swift, TypeScript, and JavaS…
Cmux No Hacky Sleeps Passed PASS. The pull request changes Python runtime code and Python tests only. The production change replaces asyncio.shield(future) with the existing _await_cleanup(future) and introduces no sleep, ti…
Cmux Algorithmic Complexity Passed PASS. The PR changes only Python files. The production change replaces one await with _await_cleanup and does not add collection scans, sorting, filtering, joins, or a slower algorithm. The added co…
Cmux Swift Concurrency Passed The pull request changes only Python files: cmux-tui/bindings/python/cmux/aio.py and cmux-tui/bindings/python/tests/test_resource_api.py. The diff contains no Swift code, so it does not introduce …
Cmux Swift @Concurrent Passed PASS: The pull request changes only Python files (cmux-tui/bindings/python/cmux/aio.py and cmux-tui/bindings/python/tests/test_resource_api.py). The authoritative diff contains no Swift changes, s…
Cmux Swift Package Boundaries Passed PASS: The reviewed diff changes only cmux-tui/bindings/python/cmux/aio.py and cmux-tui/bindings/python/tests/test_resource_api.py. It contains no Swift, SwiftPM, or app-target changes, so the Swif…
Cmux Swiftpm Lockfiles Passed PASS. The reviewed diff changes only cmux-tui/bindings/python/cmux/aio.py and cmux-tui/bindings/python/tests/test_resource_api.py. It contains no SwiftPM package, Xcode project, .gitignore, work…
Cmux Swift Logging Passed The pull request changes only Python SDK code and a Python regression test: cmux-tui/bindings/python/cmux/aio.py and cmux-tui/bindings/python/tests/test_resource_api.py. The reviewed diff contains…
Cmux User-Facing Error Privacy Passed PASS. The production diff only replaces a shielded await with the existing _await_cleanup helper in cmux-tui/bindings/python/cmux/aio.py; it adds no user-facing error, alert, command output, API e…
Cmux Full Internationalization Passed The pull request changes only Python async cleanup logic and a regression test. It introduces no Swift UI text, app catalog or Info.plist entries, web UI/API copy, metadata, markdown, changelog, or lo…
Cmux Swiftui State Layout Passed PASS. The pull request changes only Python SDK code and Python tests. It contains no SwiftUI, ObservableObject, @Published, GeometryReader, list-row store, or render-time state changes. The SwiftUI st…
Cmux Architecture Rethink Passed PASS: The pull request changes only Python SDK code and Python tests. It introduces no Swift architecture change, so the Swift architectural-rethink failure conditions do not apply.
Cmux Swift Auxiliary Window Close Shortcuts Passed PASS: The pull request changes only Python files: cmux-tui/bindings/python/cmux/aio.py and cmux-tui/bindings/python/tests/test_resource_api.py. It adds no Swift code and does not add or change any…
Cmux Source Artifacts Passed The PR changes only cmux-tui/bindings/python/cmux/aio.py and cmux-tui/bindings/python/tests/test_resource_api.py. These are hand-written source and regression-test files. The diff adds no logs, sc…
Cmux No Test Or Debug Seam In Production Source Passed The pull request changes only two Python files: cmux-tui/bindings/python/cmux/aio.py and cmux-tui/bindings/python/tests/test_resource_api.py. It changes no Swift file under a production Sources/…
Description check Passed The description clearly explains the problem, the fix, the regression coverage, test results, limitations, and changelog entry. It omits the required Summary heading, Proof section, and Checklist, alt…
Full details: Title check

Explanation

The title "fix(python): drain requests after repeated cancellation" names the main change: the Python SDK async client now waits for its request worker to drain when the caller cancels repeatedly. It matches the raw summary (_run_control drains its executor future via _await_cleanup) and the objectives. It is specific and uses a conventional-commit prefix. Minor note: "drain requests" is slightly less precise than "drain request worker", but the title is still clearly related to the change.

Full details: Cmux Cloud Persistent Session And Early Input

Explanation

PASS: The diff changes only Python request cancellation cleanup and adds a local Unix-socket regression test. It does not change Cloud terminal creation, persistent transport, renderer admission, input routing, auth, idempotency, revision fences, or leases. No failure condition in the rule is introduced.

Full details: Cmux Swift Actor Isolation

Explanation

The pull request changes only two Python files: cmux-tui/bindings/python/cmux/aio.py and cmux-tui/bindings/python/tests/test_resource_api.py. The reviewed diff contains no Swift files, so it does not introduce or worsen Swift actor isolation issues.

Full details: Cmux Swift Blocking Runtime

Explanation

PASS: The pull request changes only Python files: cmux-tui/bindings/python/cmux/aio.py and cmux-tui/bindings/python/tests/test_resource_api.py. It introduces no production Swift changes. The test-only asyncio.sleep(0) is deterministic test scaffolding and is explicitly allowed by the check.

Full details: Cmux Browser Automation Off-Main

Explanation

PASS: The pull request changes only Python async request cleanup and its regression test. The diff introduces no browser socket commands, WebKit/AppKit access, main-actor routing, worker-lane routing, or browser policy coverage concerns. The browser automation rule is therefore not applicable.

Full details: Cmux Cache Substitution Correctness

Explanation

PASS: The reviewed diff changes only Python files (cmux-tui/bindings/python/cmux/aio.py and its Python test). The cache-substitution condition applies only to production Swift, TypeScript, and JavaScript changes, so it is not applicable.

Full details: Cmux No Hacky Sleeps

Explanation

PASS. The pull request changes Python runtime code and Python tests only. The production change replaces asyncio.shield(future) with the existing _await_cleanup(future) and introduces no sleep, timer, polling loop, or wall-clock wait. The only new asyncio.sleep(0) is deterministic test-only scaffolding, which the rule allows.

Full details: Cmux Algorithmic Complexity

Explanation

PASS. The PR changes only Python files. The production change replaces one await with _await_cleanup and does not add collection scans, sorting, filtering, joins, or a slower algorithm. The added collection of test code is test-only scaffolding, which the rule explicitly excludes.

Full details: Cmux Swift Concurrency

Explanation

The pull request changes only Python files: cmux-tui/bindings/python/cmux/aio.py and cmux-tui/bindings/python/tests/test_resource_api.py. The diff contains no Swift code, so it does not introduce or expand any listed Swift concurrency pattern.

Full details: Cmux Swift `@Concurrent`

Explanation

PASS: The pull request changes only Python files (cmux-tui/bindings/python/cmux/aio.py and cmux-tui/bindings/python/tests/test_resource_api.py). The authoritative diff contains no Swift changes, so the @concurrent rule does not apply.

Full details: Cmux Swift Package Boundaries

Explanation

PASS: The reviewed diff changes only cmux-tui/bindings/python/cmux/aio.py and cmux-tui/bindings/python/tests/test_resource_api.py. It contains no Swift, SwiftPM, or app-target changes, so the Swift package boundary rule is not applicable.

Full details: Cmux Swiftpm Lockfiles

Explanation

PASS. The reviewed diff changes only cmux-tui/bindings/python/cmux/aio.py and cmux-tui/bindings/python/tests/test_resource_api.py. It contains no SwiftPM package, Xcode project, .gitignore, workflow, dependency, or Package.resolved changes, so the SwiftPM lockfile conditions do not apply.

Full details: Cmux Swift Logging

Explanation

The pull request changes only Python SDK code and a Python regression test: cmux-tui/bindings/python/cmux/aio.py and cmux-tui/bindings/python/tests/test_resource_api.py. The reviewed diff contains no Swift files and adds or changes no logging.

Full details: Cmux User-Facing Error Privacy

Explanation

PASS. The production diff only replaces a shielded await with the existing _await_cleanup helper in cmux-tui/bindings/python/cmux/aio.py; it adds no user-facing error, alert, command output, API error body, or recovery text. The added assertion text is test-only, which the rule allows. No changed text exposes implementation details or sensitive data.

Full details: Cmux Full Internationalization

Explanation

The pull request changes only Python async cleanup logic and a regression test. It introduces no Swift UI text, app catalog or Info.plist entries, web UI/API copy, metadata, markdown, changelog, or locale-dependent user-facing data. The added strings are test assertion/fixture text, which the rule allows.

Full details: Cmux Swiftui State Layout

Explanation

PASS. The pull request changes only Python SDK code and Python tests. It contains no SwiftUI, ObservableObject, @Published, GeometryReader, list-row store, or render-time state changes. The SwiftUI state-layout check is not applicable.

Full details: Cmux Swift Auxiliary Window Close Shortcuts

Explanation

PASS: The pull request changes only Python files: cmux-tui/bindings/python/cmux/aio.py and cmux-tui/bindings/python/tests/test_resource_api.py. It adds no Swift code and does not add or change any cmux-owned window, window identifier, or close-shortcut ownership.

Full details: Cmux Source Artifacts

Explanation

The PR changes only cmux-tui/bindings/python/cmux/aio.py and cmux-tui/bindings/python/tests/test_resource_api.py. These are hand-written source and regression-test files. The diff adds no logs, screenshots, recordings, temporary directories, caches, build output, dependency checkouts, or other source-control artifacts.

Full details: Cmux No Test Or Debug Seam In Production Source

Explanation

The pull request changes only two Python files: cmux-tui/bindings/python/cmux/aio.py and cmux-tui/bindings/python/tests/test_resource_api.py. It changes no Swift file under a production Sources/ path, so this check is not applicable.

Full details: Description check

Explanation

The description clearly explains the problem, the fix, the regression coverage, test results, limitations, and changelog entry. It omits the required Summary heading, Proof section, and Checklist, although the opening paragraphs provide the summary and the testing section documents the non-user-visible scope and verification.

Finishing Touches: 💡 1
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • 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

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@austinywang

austinywang commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Update from the quality audit: #25411 is the active PR. Maintainer edits to the contributor fork succeeded with a plain push; my earlier claim that the fork could not be updated was incorrect. Duplicate #25747 is closed. See the audit update for the rebase and passing 119-test Python suite.

@austinywang

Copy link
Copy Markdown
Contributor

The quality audit corrected my earlier claim about fork access: maintainer edits are enabled, and a plain push to BlueRaddish/cmux:fix/oct26a-python-cancel-drain succeeded. This original PR is the active review target again; I am closing my duplicate #25747. Thank you @BlueRaddish for the original fix and behavioral regression; both remain unchanged and retain your authorship.

The branch is rebased onto main at 36540f6194b746d48d47aa8963adbd0f1cd35cdb. Merge commits preserve the previously published ancestry so the update required no force push. The diff remains one production-line change and the socket regression test.

The full Python suite now passes all 119 tests with zero skips, including the packaging test, in an isolated Python 3.13.3 environment with setuptools 84.2.1. The earlier local packaging error was an unmet build prerequisite; no test, assertion, timeout, or retry policy was changed. Fresh CI is running on 01c92e9330400f97f7b168ce07798ae10a3b80b5.

Regarding CodeRabbit's docstring-coverage advisory: this change adds no public API. The reused _await_cleanup helper already documents deferred and repeated cancellation, and _run_control already comments on worker ownership and error precedence. The regression and its local fixture follow the neighboring test style. Adding docstrings to unrelated functions counted by the advisory would not clarify this change, so I am leaving those functions unchanged. Both PRs currently have no inline review threads to resolve.

@austinywang

Copy link
Copy Markdown
Contributor

@coderabbitai full review

The incremental review reported that it could not recover its checkpoint after the rebase. Please review current head 01c92e9330400f97f7b168ce07798ae10a3b80b5 against main; the source diff remains the same two Python files.

The Cursor Bugbot comment reports disabled on-demand billing, rather than a code finding. That account setting is outside this PR; I am preserving the existing checks and obtaining an independent structured code review alongside CodeRabbit. The docstring-coverage advisory is addressed in the audit update above.

@coderabbitai

coderabbitai Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
⚠️ Action not completed

Review skipped: 361 files exceed the limit of 300.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 28 minutes.

@austinywang

Copy link
Copy Markdown
Contributor

@coderabbitai full review

The previous full-review refusal came from GitHub retaining base SHA c0a00581d66f425cdb55bf1a4a9c349aca554668. Reapplying the existing main base refreshed the comparison to 36540f6194b746d48d47aa8963adbd0f1cd35cdb; the PR API now reports exactly 2 changed files, matching git diff origin/main...HEAD. Please review the corrected comparison at unchanged head 01c92e9330400f97f7b168ce07798ae10a3b80b5.

@austinywang

Copy link
Copy Markdown
Contributor

Ready for review: root cause a second caller cancellation interrupts the single shielded cleanup wait, letting the async request return while its executor worker is still draining; fix reuse _await_cleanup to await that same worker to completion before propagating cancellation; tests the focused regression fails before the fix and passes on the final head, all 119 Python SDK tests pass with zero skips, and all 148 shared conformance cases pass with zero failures or skips; confidence high.

Final audit at 01c92e9330400f97f7b168ce07798ae10a3b80b5:

  • Current with main at 36540f6194b746d48d47aa8963adbd0f1cd35cdb, no conflicts, clean worktree, and GitHub reports MERGEABLE / CLEAN. The update used a plain push to the original contributor branch. Duplicate fix(python): drain requests after repeated cancellation #25747 is closed.
  • The diff remains one production-line repair and its behavioral socket regression. There is no workaround, request retry, timeout increase, weakened assertion, or skipped Python test. The test proves the worker remains pending until cancellation acknowledgment and the same client remains usable afterward.
  • Python 3.9 package CI: 119 passed. The local Python 3.13.3 suite also passed all 119 tests after satisfying the declared setuptools prerequisite. The same focused command fails on test-only commit dcfb31e186c700effcef0d73872adaccbc255d6a with request worker was not drained and passes on the final head.
  • Hosted static recipe: 16/16 checks passed. Seven-language live conformance: 148 passed, zero failed, zero skipped. All applicable CI checks are green.
  • Independent structured autoreview and repository policy checks both passed with no actionable findings. There are zero unresolved review threads. CodeRabbit's docstring advisory has a reasoned reply; its new review was service-limited, and Cursor's billing notice is an account issue rather than a code finding. No check or review configuration was disabled.

The final pass found nothing left to repair. The original contributor's fix and authorship are preserved.

This branch has not been deployed

No deployments
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.

2 participants