Studio: ignore unsupported env proxy during Studio startup (#6102)
* fix: ignore unsupported env proxy during Studio startup * fix: handle missing socksio env proxy at startup * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Match printf logging style and inline the proxy predicate for PR #6102 * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Daniel Han <danielhanchen@gmail.com>
This commit is contained in:
parent
2db9fad4b5
commit
49024462f3
2 changed files with 98 additions and 3 deletions
|
|
@ -469,9 +469,24 @@ def _apply_mistral_reasoning_controls(
|
|||
|
||||
|
||||
# Shared client reused across all requests for HTTP connection pooling.
|
||||
# Auth headers and timeouts are per-request, so one client handles every
|
||||
# provider without storing credentials.
|
||||
_http_client = httpx.AsyncClient()
|
||||
# Auth headers and timeouts are passed per-request, so a single client
|
||||
# handles every provider without storing credentials.
|
||||
def _create_shared_http_client() -> httpx.AsyncClient:
|
||||
# Unsupported env proxy schemes (socks:// etc) raise at construction and
|
||||
# would crash Studio startup (#6090); retry ignoring env proxies instead.
|
||||
try:
|
||||
return httpx.AsyncClient()
|
||||
except (ImportError, ValueError) as exc:
|
||||
exc_str = str(exc)
|
||||
if "Unknown scheme for proxy URL" not in exc_str and "socksio" not in exc_str:
|
||||
raise
|
||||
logger.warning(
|
||||
"Ignoring unsupported environment proxy for the shared HTTP client: %s", exc_str
|
||||
)
|
||||
return httpx.AsyncClient(trust_env = False)
|
||||
|
||||
|
||||
_http_client = _create_shared_http_client()
|
||||
|
||||
|
||||
# Cap per-image fetch well below Gemini's ~20 MB total request budget.
|
||||
|
|
|
|||
80
studio/backend/tests/test_external_provider_proxy_env.py
Normal file
80
studio/backend/tests/test_external_provider_proxy_env.py
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
|
||||
|
||||
from pathlib import Path
|
||||
import importlib.util
|
||||
import sys
|
||||
|
||||
_BACKEND_DIR = str(Path(__file__).resolve().parent.parent)
|
||||
if _BACKEND_DIR not in sys.path:
|
||||
sys.path.insert(0, _BACKEND_DIR)
|
||||
|
||||
_EXTERNAL_PROVIDER_PATH = (
|
||||
Path(__file__).resolve().parent.parent / "core/inference/external_provider.py"
|
||||
)
|
||||
|
||||
|
||||
def _load_external_provider_module():
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
"external_provider_under_test",
|
||||
_EXTERNAL_PROVIDER_PATH,
|
||||
)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
def test_shared_http_client_ignores_unsupported_proxy_scheme(monkeypatch):
|
||||
ep_mod = _load_external_provider_module()
|
||||
calls = []
|
||||
|
||||
class FakeAsyncClient:
|
||||
def __init__(self, **kwargs):
|
||||
calls.append(kwargs)
|
||||
if kwargs.get("trust_env") is not False:
|
||||
raise ValueError("Unknown scheme for proxy URL URL('socks4://127.0.0.1:12345')")
|
||||
|
||||
monkeypatch.setattr(ep_mod.httpx, "AsyncClient", FakeAsyncClient)
|
||||
|
||||
client = ep_mod._create_shared_http_client()
|
||||
|
||||
assert isinstance(client, FakeAsyncClient)
|
||||
assert calls == [{}, {"trust_env": False}]
|
||||
|
||||
|
||||
def test_shared_http_client_ignores_missing_socksio(monkeypatch):
|
||||
ep_mod = _load_external_provider_module()
|
||||
calls = []
|
||||
|
||||
class FakeAsyncClient:
|
||||
def __init__(self, **kwargs):
|
||||
calls.append(kwargs)
|
||||
if kwargs.get("trust_env") is not False:
|
||||
raise ImportError(
|
||||
"Using SOCKS proxy, but the 'socksio' package is not installed. "
|
||||
"Make sure to install httpx using `pip install httpx[socks]`."
|
||||
)
|
||||
|
||||
monkeypatch.setattr(ep_mod.httpx, "AsyncClient", FakeAsyncClient)
|
||||
|
||||
client = ep_mod._create_shared_http_client()
|
||||
|
||||
assert isinstance(client, FakeAsyncClient)
|
||||
assert calls == [{}, {"trust_env": False}]
|
||||
|
||||
|
||||
def test_shared_http_client_reraises_other_value_errors(monkeypatch):
|
||||
ep_mod = _load_external_provider_module()
|
||||
|
||||
class FakeAsyncClient:
|
||||
def __init__(self, **kwargs):
|
||||
raise ValueError("different httpx setup error")
|
||||
|
||||
monkeypatch.setattr(ep_mod.httpx, "AsyncClient", FakeAsyncClient)
|
||||
|
||||
try:
|
||||
ep_mod._create_shared_http_client()
|
||||
except ValueError as exc:
|
||||
assert str(exc) == "different httpx setup error"
|
||||
else:
|
||||
raise AssertionError("expected ValueError")
|
||||
Loading…
Add table
Add a link
Reference in a new issue