Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/python-volume-proxy-transport.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@e2b/python-sdk": patch
---

fix(python-sdk): stop leaking per-call proxy connection pools in volume content clients

The volume content clients passed both `proxy` and the shared cached
`transport` to httpx, so with a proxy configured every volume operation mounted
a fresh, never-closed proxy transport. The proxy is already part of the cached
transport, so the client-level `proxy` argument is now dropped. Volume
transports also gained connect-level retries, matching the other transports.
6 changes: 4 additions & 2 deletions packages/python-sdk/e2b/volume/client_async/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from httpx import Limits
from httpx._types import ProxyTypes

from e2b.api import make_async_logging_event_hooks
from e2b.api import connection_retries, make_async_logging_event_hooks
from e2b.api.metadata import default_headers
from e2b.exceptions import AuthenticationException
from e2b.volume.client.client import AuthenticatedClient as AsyncVolumeApiClient
Expand Down Expand Up @@ -47,7 +47,8 @@ def get_api_client(config: VolumeConnectionConfig, **kwargs) -> AsyncVolumeApiCl
httpx.Timeout(request_timeout) if request_timeout is not None else None
),
httpx_args={
"proxy": config.proxy,
# The proxy lives in the cached transport; passing `proxy` here too
# would mount a fresh, never-closed proxy transport per client.
"transport": get_transport(config),
"event_hooks": make_async_logging_event_hooks(config.logger),
},
Expand Down Expand Up @@ -82,6 +83,7 @@ def get_transport(config: VolumeConnectionConfig) -> AsyncTransportWithLogger:
transport = AsyncTransportWithLogger(
limits=limits,
proxy=config.proxy,
retries=connection_retries,
)
loop_instances[key] = transport

Expand Down
6 changes: 4 additions & 2 deletions packages/python-sdk/e2b/volume/client_sync/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from httpx import Limits
from httpx._types import ProxyTypes

from e2b.api import make_logging_event_hooks
from e2b.api import connection_retries, make_logging_event_hooks
from e2b.api.metadata import default_headers
from e2b.exceptions import AuthenticationException
from e2b.volume.client.client import AuthenticatedClient as VolumeApiClient
Expand Down Expand Up @@ -46,7 +46,8 @@ def get_api_client(config: VolumeConnectionConfig, **kwargs) -> VolumeApiClient:
httpx.Timeout(request_timeout) if request_timeout is not None else None
),
httpx_args={
"proxy": config.proxy,
# The proxy lives in the cached transport; passing `proxy` here too
# would mount a fresh, never-closed proxy transport per client.
"transport": get_transport(config),
"event_hooks": make_logging_event_hooks(config.logger),
},
Expand Down Expand Up @@ -74,6 +75,7 @@ def get_transport(config: VolumeConnectionConfig) -> TransportWithLogger:
transport = TransportWithLogger(
limits=limits,
proxy=config.proxy,
retries=connection_retries,
)
instances[key] = transport
TransportWithLogger._thread_local.instances = instances
Expand Down
Loading