diff --git a/api/services/billing_service.py b/api/services/billing_service.py index aef5ae2f02b..0ac38c9257b 100644 --- a/api/services/billing_service.py +++ b/api/services/billing_service.py @@ -21,7 +21,10 @@ 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)), + lambda: httpx.Client( + timeout=httpx.Timeout(30.0, connect=5.0), + limits=httpx.Limits(max_keepalive_connections=50, max_connections=100), + ), ) diff --git a/api/tests/unit_tests/services/test_billing_service.py b/api/tests/unit_tests/services/test_billing_service.py index a8d405ae8a3..349e81ba1f1 100644 --- a/api/tests/unit_tests/services/test_billing_service.py +++ b/api/tests/unit_tests/services/test_billing_service.py @@ -2055,3 +2055,17 @@ class TestBillingServiceSubscriptionInfoDataType: with pytest.raises(ValidationError): BillingService.get_info("tenant-type-test") + + +def test_pooled_billing_client_carries_bounded_timeout() -> None: + """Regression for #39874: the pooled billing client must carry a + read/connect timeout so a stalled Stripe / cloud-billing proxy + fails fast instead of pinning a worker. Same shape as the + JinaReader / WaterCrawl hardening that landed in PR #39860 and #39824. + """ + import services.billing_service as billing_service_module + + client = billing_service_module._http_client + assert client.timeout is not None + assert client.timeout.read == 30.0 + assert client.timeout.connect == 5.0