@@ -53,19 +53,44 @@ async def handle_async_request(self, request: httpx.Request) -> httpx.Response:
5353
5454
5555class ConnectionRetryTransport (RetryTransport ):
56- """Retry only failures establishing the connection, matching the
57- connect-only ``retries`` of the httpx transport this replaced: pyqwest
58- raises the builtin ``ConnectionError`` only before the request was
59- written, so these retries can never replay a request the API may have
60- received. The retry middleware's default policy would otherwise also
61- retry I/O errors and 429/5xx responses for idempotent methods."""
56+ """Retry only failures establishing the connection — shared by the REST
57+ API and envd RPC stacks: pyqwest raises the builtin ``ConnectionError``
58+ only before the request was written, so these retries can never replay a
59+ request the server may have received (a delivered REST call or unary RPC
60+ like ``SendInput``). This matches the connect-only ``retries`` of the
61+ httpx transports this replaced; the retry middleware's default policy
62+ would otherwise also retry I/O errors and 429/5xx responses for
63+ idempotent methods."""
6264
6365 def should_retry_response (
6466 self , request : Request , response : Union [Response , Exception ]
6567 ) -> bool :
6668 return isinstance (response , ConnectionError )
6769
6870
71+ def retrying_http_transport (
72+ proxy : Optional [ProxyConfig ],
73+ ) -> ConnectionRetryTransport :
74+ """A fresh pyqwest transport (= its own connection pool) with the SDK's
75+ shared tuning — system CA certs (without which TLS through an
76+ intercepting proxy fails), the httpx-equivalent pool limits, and
77+ connect-only retries. The REST API and envd RPC stacks each cache their
78+ own instances (pool unification is a follow-up).
79+ Requests are logged by pyqwest itself on the ``pyqwest.access`` and
80+ ``pyqwest`` loggers at ``DEBUG`` (off unless enabled) — the transport-level
81+ diagnostics httpcore used to provide. The SDK's own ``logger`` option is
82+ separate and sits above this, on the httpx client."""
83+ return ConnectionRetryTransport (
84+ HTTPTransport (
85+ tls_include_system_certs = True ,
86+ proxy = proxy .to_pyqwest () if proxy is not None else None ,
87+ pool_idle_timeout = pool_idle_timeout ,
88+ pool_max_idle_per_host = pool_max_idle_per_host ,
89+ ),
90+ max_retries = connection_retries ,
91+ )
92+
93+
6994_transport_lock = threading .Lock ()
7095# One transport (= one connection pool) per proxy; None is the direct pool.
7196# pyqwest's I/O runs on its own Rust runtime, so unlike the httpx envd
@@ -77,27 +102,12 @@ def should_retry_response(
77102def get_transport (config : ConnectionConfig ) -> "AsyncApiPyqwestTransport" :
78103 """The shared pyqwest-backed httpx transport for REST API calls. For TLS
79104 connections ALPN negotiates the HTTP version (HTTP/2 against the E2B
80- API), like the http2-enabled httpx transport this replaced.
81-
82- Requests are logged by pyqwest itself on the ``pyqwest.access`` and
83- ``pyqwest`` loggers at ``DEBUG`` (off unless enabled) — the transport-level
84- diagnostics httpcore used to provide. The SDK's own ``logger`` option is
85- separate and sits above this, on the httpx client."""
105+ API), like the http2-enabled httpx transport this replaced."""
86106 proxy = proxy_to_config (config .proxy )
87107 with _transport_lock :
88108 transport = _transports .get (proxy )
89109 if transport is None :
90- transport = AsyncApiPyqwestTransport (
91- ConnectionRetryTransport (
92- HTTPTransport (
93- tls_include_system_certs = True ,
94- proxy = proxy .to_pyqwest () if proxy is not None else None ,
95- pool_idle_timeout = pool_idle_timeout ,
96- pool_max_idle_per_host = pool_max_idle_per_host ,
97- ),
98- max_retries = connection_retries ,
99- )
100- )
110+ transport = AsyncApiPyqwestTransport (retrying_http_transport (proxy ))
101111 _transports [proxy ] = transport
102112 return transport
103113
0 commit comments