perf: use global httpx client instead of per request create new one (#34311)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
wangxiaolei
2026-04-01 01:19:32 +00:00
committed by GitHub
co-authored by autofix-ci[bot]
parent 19530e880a
commit 57f358a96b
19 changed files with 167 additions and 64 deletions
+7 -1
View File
@@ -2,8 +2,14 @@ import json
import httpx
from core.helper.http_client_pooling import get_pooled_http_client
from services.auth.api_key_auth_base import ApiKeyAuthBase, AuthCredentials
_http_client: httpx.Client = get_pooled_http_client(
"auth:jina_standalone",
lambda: httpx.Client(limits=httpx.Limits(max_keepalive_connections=50, max_connections=100)),
)
class JinaAuth(ApiKeyAuthBase):
def __init__(self, credentials: AuthCredentials):
@@ -31,7 +37,7 @@ class JinaAuth(ApiKeyAuthBase):
return {"Content-Type": "application/json", "Authorization": f"Bearer {self.api_key}"}
def _post_request(self, url, data, headers):
return httpx.post(url, headers=headers, json=data)
return _http_client.post(url, headers=headers, json=data)
def _handle_error(self, response):
if response.status_code in {402, 409, 500}:
+7 -1
View File
@@ -2,8 +2,14 @@ import json
import httpx
from core.helper.http_client_pooling import get_pooled_http_client
from services.auth.api_key_auth_base import ApiKeyAuthBase, AuthCredentials
_http_client: httpx.Client = get_pooled_http_client(
"auth:jina",
lambda: httpx.Client(limits=httpx.Limits(max_keepalive_connections=50, max_connections=100)),
)
class JinaAuth(ApiKeyAuthBase):
def __init__(self, credentials: AuthCredentials):
@@ -31,7 +37,7 @@ class JinaAuth(ApiKeyAuthBase):
return {"Content-Type": "application/json", "Authorization": f"Bearer {self.api_key}"}
def _post_request(self, url, data, headers):
return httpx.post(url, headers=headers, json=data)
return _http_client.post(url, headers=headers, json=data)
def _handle_error(self, response):
if response.status_code in {402, 409, 500}:
+7 -1
View File
@@ -10,6 +10,7 @@ from tenacity import retry, retry_if_exception_type, stop_before_delay, wait_fix
from typing_extensions import TypedDict
from werkzeug.exceptions import InternalServerError
from core.helper.http_client_pooling import get_pooled_http_client
from enums.cloud_plan import CloudPlan
from extensions.ext_database import db
from extensions.ext_redis import redis_client
@@ -18,6 +19,11 @@ from models import Account, TenantAccountJoin, TenantAccountRole
logger = logging.getLogger(__name__)
_http_client: httpx.Client = get_pooled_http_client(
"billing:default",
lambda: httpx.Client(limits=httpx.Limits(max_keepalive_connections=50, max_connections=100)),
)
class SubscriptionPlan(TypedDict):
"""Tenant subscriptionplan information."""
@@ -131,7 +137,7 @@ class BillingService:
headers = {"Content-Type": "application/json", "Billing-Api-Secret-Key": cls.secret_key}
url = f"{cls.base_url}{endpoint}"
response = httpx.request(method, url, json=json, params=params, headers=headers, follow_redirects=True)
response = _http_client.request(method, url, json=json, params=params, headers=headers, follow_redirects=True)
if method == "GET" and response.status_code != httpx.codes.OK:
raise ValueError("Unable to retrieve billing information. Please try again later or contact support.")
if method == "PUT":
+18 -7
View File
@@ -9,12 +9,23 @@ import httpx
from flask_login import current_user
from core.helper import encrypter
from core.helper.http_client_pooling import get_pooled_http_client
from core.rag.extractor.firecrawl.firecrawl_app import CrawlStatusResponse, FirecrawlApp, FirecrawlDocumentData
from core.rag.extractor.watercrawl.provider import WaterCrawlProvider
from extensions.ext_redis import redis_client
from extensions.ext_storage import storage
from services.datasource_provider_service import DatasourceProviderService
# Reuse pooled HTTP clients to avoid creating new connections per request and ease testing.
_jina_http_client: httpx.Client = get_pooled_http_client(
"website:jinareader",
lambda: httpx.Client(limits=httpx.Limits(max_keepalive_connections=50, max_connections=100)),
)
_adaptive_http_client: httpx.Client = get_pooled_http_client(
"website:adaptivecrawl",
lambda: httpx.Client(limits=httpx.Limits(max_keepalive_connections=50, max_connections=100)),
)
@dataclass
class CrawlOptions:
@@ -225,7 +236,7 @@ class WebsiteService:
@classmethod
def _crawl_with_jinareader(cls, request: CrawlRequest, api_key: str) -> dict[str, Any]:
if not request.options.crawl_sub_pages:
response = httpx.get(
response = _jina_http_client.get(
f"https://r.jina.ai/{request.url}",
headers={"Accept": "application/json", "Authorization": f"Bearer {api_key}"},
)
@@ -233,7 +244,7 @@ class WebsiteService:
raise ValueError("Failed to crawl:")
return {"status": "active", "data": response.json().get("data")}
else:
response = httpx.post(
response = _adaptive_http_client.post(
"https://adaptivecrawl-kir3wx7b3a-uc.a.run.app",
json={
"url": request.url,
@@ -296,7 +307,7 @@ class WebsiteService:
@classmethod
def _get_jinareader_status(cls, job_id: str, api_key: str) -> dict[str, Any]:
response = httpx.post(
response = _adaptive_http_client.post(
"https://adaptivecrawlstatus-kir3wx7b3a-uc.a.run.app",
headers={"Content-Type": "application/json", "Authorization": f"Bearer {api_key}"},
json={"taskId": job_id},
@@ -312,7 +323,7 @@ class WebsiteService:
}
if crawl_status_data["status"] == "completed":
response = httpx.post(
response = _adaptive_http_client.post(
"https://adaptivecrawlstatus-kir3wx7b3a-uc.a.run.app",
headers={"Content-Type": "application/json", "Authorization": f"Bearer {api_key}"},
json={"taskId": job_id, "urls": list(data.get("processed", {}).keys())},
@@ -374,7 +385,7 @@ class WebsiteService:
@classmethod
def _get_jinareader_url_data(cls, job_id: str, url: str, api_key: str) -> dict[str, Any] | None:
if not job_id:
response = httpx.get(
response = _jina_http_client.get(
f"https://r.jina.ai/{url}",
headers={"Accept": "application/json", "Authorization": f"Bearer {api_key}"},
)
@@ -383,7 +394,7 @@ class WebsiteService:
return dict(response.json().get("data", {}))
else:
# Get crawl status first
status_response = httpx.post(
status_response = _adaptive_http_client.post(
"https://adaptivecrawlstatus-kir3wx7b3a-uc.a.run.app",
headers={"Content-Type": "application/json", "Authorization": f"Bearer {api_key}"},
json={"taskId": job_id},
@@ -393,7 +404,7 @@ class WebsiteService:
raise ValueError("Crawl job is not completed")
# Get processed data
data_response = httpx.post(
data_response = _adaptive_http_client.post(
"https://adaptivecrawlstatus-kir3wx7b3a-uc.a.run.app",
headers={"Content-Type": "application/json", "Authorization": f"Bearer {api_key}"},
json={"taskId": job_id, "urls": list(status_data.get("processed", {}).keys())},