fix(sdk): stop command event iterator at terminal end event#1392
fix(sdk): stop command event iterator at terminal end event#1392mishushakov wants to merge 4 commits into
Conversation
Terminate the background command event iterator as soon as the terminal `end` event is received instead of waiting for envd to close the HTTP stream, so `CommandHandle.wait()` returns promptly once the result is known. Release the underlying HTTP stream/connection deterministically in all paths (normal completion, exception, disconnect) to avoid exhausting the connection pool. Applied to JS, Python async, and Python sync SDKs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PR SummaryMedium Risk Overview JS Unit tests were added for JS and Python async/sync; changeset bumps Reviewed by Cursor Bugbot for commit 869f048. Bugbot is set up for automated code reviews on this repo. Configure here. |
🦋 Changeset detectedLatest commit: 869f048 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Package ArtifactsBuilt from 19ef195. Download artifacts from this workflow run. JS SDK ( npm install ./e2b-2.27.2-mishushakov-command-iterator-stop-on-end.0.tgzCLI ( npm install ./e2b-cli-2.10.4-mishushakov-command-iterator-stop-on-end.0.tgzPython SDK ( pip install ./e2b-2.25.1+mishushakov.command.iterator.stop.on.end-py3-none-any.whl |
The connect-es response iterator omits return()/throw(), so early-returning from it on the end event left the transport's per-call deadline timer (and the connection) dangling until GC — which Deno's leak detector flags as a test failure. Instead, cancel the request on the end event so the next read settles immediately and the transport runs its cleanup; the resulting cancellation error is ignored once the result is known. Updated the unit test to faithfully model the connect-es iterator (no return(), settles only on cancel) so it actually exercises the leak. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Keep one "stops at end event" case per SDK; drop the disconnect/exception variants that mostly restated the SDK-side control flow. Real envd behavior is covered by the live command tests and the Deno leak test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Problem
A background command handle reads the command's output stream in a loop. envd sends a terminal
endevent (carrying the exit code) and is then expected to close the HTTP stream. The iterator recorded the result on theendevent but kept awaiting the next stream event, soCommandHandle.wait()only unblocked when envd actually closed the stream — and if that close was delayed,wait()hung past the point the result was already known. Separately, the underlying stream held its HTTP/TCP connection open until GC, which can exhaust the connection pool (max_connections=2000) in workloads creating many handles. This is thewait()-blocking / connection-release facet of #1034.Changes
endevent is received, regardless of stream-close timing.disconnect()):aclose()/close(), so_handle_eventscloses it in afinally.disconnect()(async) now cancels the task and lets thatfinallyclose the stream, avoiding the concurrent-accessRuntimeErrorthat previously disabledaclose()there.return()/throw(), and the transport only clears its per-call deadline timer + connection on a settled read — never on an abandoned iterator. So instead of returning early, we cancel the request on theendevent; the next read then settles immediately and the transport runs its cleanup. The resulting cancellation error is ignored once the result is known. (Returning early leaked a timer, which Deno's leak detector flagged as a CI failure.)e2band@e2b/python-sdk.Usage
No API change — existing code benefits automatically:
kill()semantics are unchanged; the child-process-survival facet of #1034 is handled separately.🤖 Generated with Claude Code