Refresh SDK connection pools when network settings change

This commit is contained in:
Palash Debnath
2026-09-28 17:30:10 -07:00
parent 7088f2fe42
commit a48e2591ed
3 changed files with 30 additions and 5 deletions
+10 -1
View File
@@ -34,8 +34,17 @@ def _check_sdk_request(request):
raise ValueError("SDK provider requests require HTTPS outside localhost")
@lru_cache(maxsize=1)
def _sdk_http_client():
# Settings can update proxies without restarting the backend. Retire the
# previous pool without closing responses still being streamed from it.
keys = ("HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", "NO_PROXY",
"http_proxy", "https_proxy", "all_proxy", "no_proxy",
"SSL_CERT_FILE", "SSL_CERT_DIR", "REQUEST_METHOD")
return _sdk_http_client_for_env(tuple(os.environ.get(key) for key in keys))
@lru_cache(maxsize=1)
def _sdk_http_client_for_env(network_env):
# A shared thread-safe pool also keeps streaming responses alive after
# completion() returns. It carries no provider credentials of its own.
import httpx
+2
View File
@@ -153,3 +153,5 @@ Anthropic, Bedrock, and Vertex requests.
The shared HTTP client bypasses environment proxies for loopback requests so local
prompts stay local, preserves proxy settings for remote HTTPS providers, and never
stores response cookies between provider requests.
Changing proxy settings refreshes the pool for subsequent requests while existing
streams keep their original connections until they finish.
+18 -4
View File
@@ -165,7 +165,7 @@ def test_anthropic_does_not_follow_credentialed_redirect(registry):
def test_sdk_pool_keeps_loopback_direct_and_does_not_persist_cookies(monkeypatch, proxy_enabled):
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from threading import Thread
from services.llm_transport import _sdk_http_client
from services.llm_transport import _sdk_http_client_for_env
seen = []
class Handler(BaseHTTPRequestHandler):
def log_message(self, *args): pass
@@ -182,7 +182,7 @@ def test_sdk_pool_keeps_loopback_direct_and_does_not_persist_cookies(monkeypatch
server = ThreadingHTTPServer(("127.0.0.1", 0), Handler)
thread = Thread(target=server.serve_forever, daemon=True); thread.start()
try:
with _sdk_http_client.__wrapped__() as client:
with _sdk_http_client_for_env.__wrapped__(()) as client:
for _ in range(2):
assert client.get(f"http://127.0.0.1:{server.server_port}/", timeout=2).status_code == 200
assert not list(client.cookies.jar)
@@ -195,7 +195,7 @@ def test_sdk_remote_https_still_uses_environment_proxy(monkeypatch):
import httpx
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from threading import Thread
from services.llm_transport import _sdk_http_client
from services.llm_transport import _sdk_http_client_for_env
seen = []
class Handler(BaseHTTPRequestHandler):
def log_message(self, *args): pass
@@ -211,9 +211,23 @@ def test_sdk_remote_https_still_uses_environment_proxy(monkeypatch):
monkeypatch.setenv("NO_PROXY", "")
monkeypatch.setenv("no_proxy", "")
try:
with _sdk_http_client.__wrapped__() as client:
with _sdk_http_client_for_env.__wrapped__(()) as client:
with pytest.raises(httpx.ProxyError, match="502"):
client.get("https://provider.invalid/", timeout=2)
assert seen == ["provider.invalid:443"]
finally:
server.shutdown(); server.server_close(); thread.join(timeout=2)
def test_sdk_pool_refreshes_after_proxy_change_without_closing_active_streams(monkeypatch):
from services.llm_transport import _sdk_http_client
monkeypatch.setenv("HTTPS_PROXY", "http://127.0.0.1:8011")
monkeypatch.setenv("https_proxy", "http://127.0.0.1:8011")
first = _sdk_http_client()
assert _sdk_http_client() is first
monkeypatch.setenv("HTTPS_PROXY", "http://127.0.0.1:8012")
monkeypatch.setenv("https_proxy", "http://127.0.0.1:8012")
second = _sdk_http_client()
assert second is not first
assert not first.is_closed
assert not second.is_closed