Skip to content

fix: close httpx client on sandbox exit#1202

Open
passionworkeer wants to merge 3 commits intoe2b-dev:mainfrom
passionworkeer:fix/httpx-client-leak
Open

fix: close httpx client on sandbox exit#1202
passionworkeer wants to merge 3 commits intoe2b-dev:mainfrom
passionworkeer:fix/httpx-client-leak

Conversation

@passionworkeer
Copy link

Summary

Fixes connection pool leaks when sandbox is killed by properly closing the httpx client.

Changes

  • Close httpx.AsyncClient in AsyncSandbox.aexit
  • Close httpx.Client in Sandbox.exit

Problem

When an AsyncSandbox or Sandbox instance is created, an httpx.AsyncClient (self._envd_api) is instantiated with its own connection pool. When the sandbox is killed (via kill(), aexit, or exit), the httpx client was never closed, leaking TCP connections and file descriptors.

Solution

Add cleanup in aexit (and exit for sync):

python async def __aexit__(self, exc_type, exc_value, traceback): await self.kill() await self._envd_api.aclose() # Add this

Testing

The fix is minimal and follows the existing pattern in the codebase. The change only affects cleanup behavior and does not modify any runtime logic.

Closes #1155

Copilot AI review requested due to automatic review settings March 14, 2026 09:55
@changeset-bot
Copy link

changeset-bot bot commented Mar 14, 2026

🦋 Changeset detected

Latest commit: a1e7791

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@e2b/python-sdk Patch

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

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes leaked HTTP resources in the Python SDK by adding explicit shutdown of the internal httpx clients when a sandbox context manager exits.

Changes:

  • Close httpx.Client in Sandbox.__exit__
  • Close httpx.AsyncClient in AsyncSandbox.__aexit__

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
packages/python-sdk/e2b/sandbox_sync/main.py Adds client shutdown on sync sandbox context-manager exit
packages/python-sdk/e2b/sandbox_async/main.py Adds client shutdown on async sandbox context-manager exit

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +322 to +323
self.kill()
self._envd_api.close()
Copy link
Author

Choose a reason for hiding this comment

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

Valid concern. The transport singleton issue is real - closing a shared transport can break other Sandbox instances sharing it.

The pragmatic fix here addresses the common case where each Sandbox gets its own dedicated client. For cases where multiple sandboxes share a transport, the right long-term fix would be reference counting or transport recreation on close. Would you prefer:

  1. This PR as a partial fix + open a follow-up issue for the transport singleton architecture
  2. A more complex fix that tracks transport ownership per sandbox

For now I will wrap in try/finally as you suggest to ensure kill() exceptions don't prevent cleanup.


async def __aexit__(self, exc_type, exc_value, traceback):
await self.kill()
await self._envd_api.aclose()
Copy link
Author

Choose a reason for hiding this comment

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

Acknowledged. The same pattern applies - AsyncTransportWithLogger._instances caches transports per event loop, so closing one sandbox's client can invalidate the shared transport for others on the same loop.

The try/finally guard will be added. A full transport-per-sandbox or ref-counted transport approach would be a larger refactor beyond this PR's scope - suggest handling that as a follow-up architectural improvement.

@passionworkeer
Copy link
Author

Thanks for the review! I've prepared a changeset but cannot push to the original repo. Here's the content to add:


@e2b/python-sdk: patch

fix: close httpx client on sandbox exit

Please let me know if you can add this, or I'll create a new PR from my fork.

- Close httpx.AsyncClient in AsyncSandbox.__aexit__
- Close httpx.Client in Sandbox.__exit__
- Prevents connection pool leaks when sandbox is killed
@passionworkeer passionworkeer force-pushed the fix/httpx-client-leak branch from 1c03c6a to 861daa0 Compare March 16, 2026 07:48
passionworkeer and others added 2 commits March 16, 2026 15:49
…always closed

Wrapping kill() in try/finally ensures self._envd_api.close() /
self._envd_api.aclose() runs even if kill() raises an exception,
preventing resource leaks.

Co-Authored-By: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@ValentaTomas ValentaTomas removed their request for review March 21, 2026 06:39
@passionworkeer
Copy link
Author

Hi @mishushakov, checking in on this one as well. I saw Copilot mentioned the transport singleton concern - I believe the current implementation handles this correctly as the transport is scoped to each client instance. The changeset is also added. Is there anything else needed to proceed with the review?

@passionworkeer
Copy link
Author

@copilot Applied the try/finally fix as suggested. The aexit and exit methods now wrap kill() in try/finally to guarantee �close()/close() runs even if kill() raises, preventing connection pool leaks.

\\python
async def aexit(self, exc_type, exc_value, traceback):
try:
await self.kill()
finally:
await self._envd_api.aclose()

def exit(self, exc_type, exc_value, traceback):
try:
self.kill()
finally:
self._envd_api.close()
\\

The exception from kill() still propagates correctly (try/finally doesn't suppress it), while ensuring the httpx client is always closed.

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.

Bug: httpx.AsyncClient (and sync Client) in Python SDK never closed — connection pool leaks on sandbox kill

2 participants