fix(payments): restore default provider connections

This commit is contained in:
BADtochka
2026-06-06 17:53:16 +03:00
parent a75d2d7ac0
commit e3f35a461c
2 changed files with 5 additions and 18 deletions
@@ -5,15 +5,10 @@ import json
import logging import logging
from typing import Any, Callable, Dict, Mapping, Optional, Tuple from typing import Any, Callable, Dict, Mapping, Optional, Tuple
from aiohttp import ClientError, ClientSession, ClientTimeout, TCPConnector, TraceConfig from aiohttp import ClientError, ClientSession, ClientTimeout, TraceConfig
SuccessCheck = Callable[[int, Any], bool] SuccessCheck = Callable[[int, Any], bool]
_TRANSPORT_ATTEMPTS = 2 _TRANSPORT_ATTEMPTS = 2
_PAYMENT_REQUEST_USER_AGENT = (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/125.0.0.0 Safari/537.36"
)
def http_ok(status: int, _body: Any) -> bool: def http_ok(status: int, _body: Any) -> bool:
@@ -120,27 +115,21 @@ class HttpClientMixin:
``__init__`` and inherits ``_get_session`` / ``close``. The session is ``__init__`` and inherits ``_get_session`` / ``close``. The session is
created on first use and recreated transparently if it was closed. created on first use and recreated transparently if it was closed.
Payment provider calls are infrequent but user-facing, so the default Provider API calls are traced so callers can retry transport failures only
connector does not reuse TCP connections. This avoids intermittent hangs when aiohttp has not sent request headers yet.
on stale keep-alive sockets after long idle periods.
""" """
_timeout: ClientTimeout _timeout: ClientTimeout
_session: Optional[ClientSession] _session: Optional[ClientSession]
_connector_force_close: bool
def _init_http_client(self, *, total_timeout: float = 20.0) -> None: def _init_http_client(self, *, total_timeout: float = 20.0) -> None:
self._timeout = ClientTimeout(total=total_timeout) self._timeout = ClientTimeout(total=total_timeout)
self._session = None self._session = None
self._connector_force_close = True
async def _get_session(self) -> ClientSession: async def _get_session(self) -> ClientSession:
if self._session is None or self._session.closed: if self._session is None or self._session.closed:
connector = TCPConnector(force_close=self._connector_force_close)
self._session = ClientSession( self._session = ClientSession(
timeout=self._timeout, timeout=self._timeout,
connector=connector,
headers={"User-Agent": _PAYMENT_REQUEST_USER_AGENT},
trace_configs=[_payment_trace_config()], trace_configs=[_payment_trace_config()],
) )
return self._session return self._session
+2 -4
View File
@@ -2,7 +2,6 @@ import unittest
from bot.payment_providers.shared.http_client import ( from bot.payment_providers.shared.http_client import (
HttpClientMixin, HttpClientMixin,
_PAYMENT_REQUEST_USER_AGENT,
_should_retry_transport_error, _should_retry_transport_error,
) )
@@ -13,13 +12,12 @@ class _DummyHttpClient(HttpClientMixin):
class PaymentHttpClientTests(unittest.IsolatedAsyncioTestCase): class PaymentHttpClientTests(unittest.IsolatedAsyncioTestCase):
async def test_http_client_does_not_reuse_provider_tcp_connections(self): async def test_http_client_tracks_sent_headers_for_safe_retries(self):
client = _DummyHttpClient() client = _DummyHttpClient()
try: try:
session = await client._get_session() session = await client._get_session()
self.assertTrue(session.connector.force_close) self.assertFalse(session.connector.force_close)
self.assertTrue(session.trace_configs) self.assertTrue(session.trace_configs)
self.assertEqual(session.headers["User-Agent"], _PAYMENT_REQUEST_USER_AGENT)
finally: finally:
await client.close() await client.close()