diff --git a/.gitignore b/.gitignore index 894a44cc..799b90cf 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,6 @@ venv.bak/ # mypy .mypy_cache/ + +# IDE +.idea/ diff --git a/stellar_sdk/client/aiohttp_client.py b/stellar_sdk/client/aiohttp_client.py index d14daebe..5a72a6d4 100644 --- a/stellar_sdk/client/aiohttp_client.py +++ b/stellar_sdk/client/aiohttp_client.py @@ -6,14 +6,13 @@ import aiohttp from aiohttp_sse_client.client import EventSource +from . import defines from .base_async_client import BaseAsyncClient from .response import Response from ..__version__ import __version__ logger = logging.getLogger(__name__) -# four ledgers sec, let's retry faster and not wait 60 secs. -DEFAULT_REQUEST_TIMEOUT = 20 DEFAULT_NUM_RETRIES = 3 DEFAULT_BACKOFF_FACTOR = 0.5 USER_AGENT = "py-stellar-sdk/%s/AiohttpClient" % __version__ @@ -30,7 +29,8 @@ class AiohttpClient(BaseAsyncClient): which represents the interface for making requests to a server instance. :param pool_size: persistent connection to Horizon and connection pool - :param request_timeout: the timeout for all requests + :param request_timeout: the timeout for all GET requests + :param post_timeout: the timeout for all POST requests :param backoff_factor: a backoff factor to apply between attempts after the second try :param user_agent: the server can use it to identify you """ @@ -38,13 +38,15 @@ class AiohttpClient(BaseAsyncClient): def __init__( self, pool_size: Optional[int] = None, - request_timeout: float = DEFAULT_REQUEST_TIMEOUT, + request_timeout: float = defines.DEFAULT_GET_TIMEOUT_SECONDS, + post_timeout: float = defines.DEFAULT_POST_TIMEOUT_SECONDS, backoff_factor: Optional[float] = DEFAULT_BACKOFF_FACTOR, user_agent: Optional[str] = None, **kwargs ) -> None: self.backoff_factor: Optional[float] = backoff_factor self.request_timeout: float = request_timeout + self.post_timeout: float = post_timeout # init session if pool_size is None: @@ -99,7 +101,7 @@ async def post(self, url: str, data: Dict[str, str] = None) -> Response: :raise: :exc:`ConnectionError ` """ try: - response = await self._session.post(url, data=data) + response = await self._session.post(url, data=data, timeout=aiohttp.ClientTimeout(total=self.post_timeout)) return Response( status_code=response.status, text=await response.text(), diff --git a/stellar_sdk/client/defines.py b/stellar_sdk/client/defines.py new file mode 100644 index 00000000..ffa0fef0 --- /dev/null +++ b/stellar_sdk/client/defines.py @@ -0,0 +1,7 @@ +# Two ledgers average time + 1 sec +DEFAULT_GET_TIMEOUT_SECONDS = 11 + +# https://github.com/stellar/go/blob/7c4596db1ad107f770bd6e5a694ea5129440cb1e/services/horizon/internal/txsub/system.go#L314 +_HORIZON_SUBMIT_TRANSACTION_API_TIMEOUT_SECONDS = 30 +# POST is only used for submitting transactions to Horizon. Therefore we take the Horizon value with some grace. +DEFAULT_POST_TIMEOUT_SECONDS = _HORIZON_SUBMIT_TRANSACTION_API_TIMEOUT_SECONDS * 1.1 diff --git a/stellar_sdk/client/requests_client.py b/stellar_sdk/client/requests_client.py index b6f5f154..51991e2e 100644 --- a/stellar_sdk/client/requests_client.py +++ b/stellar_sdk/client/requests_client.py @@ -8,13 +8,12 @@ from urllib3.exceptions import NewConnectionError from urllib3.util import Retry +from . import defines from ..__version__ import __version__ from ..client.base_sync_client import BaseSyncClient from ..client.response import Response from ..exceptions import ConnectionError -# four ledgers sec, let's retry faster and not wait 60 secs. -DEFAULT_REQUEST_TIMEOUT = 20 DEFAULT_NUM_RETRIES = 3 DEFAULT_BACKOFF_FACTOR = 0.5 USER_AGENT = "py-stellar-sdk/%s/RequestsClient" % __version__ @@ -32,7 +31,8 @@ class RequestsClient(BaseSyncClient): :param pool_size: persistent connection to Horizon and connection pool :param num_retries: configurable request retry functionality - :param request_timeout: the timeout for all requests + :param request_timeout: the timeout for all GET requests + :param post_timeout: the timeout for all POST requests :param backoff_factor: a backoff factor to apply between attempts after the second try :param session: the request session :param stream_session: the stream request session @@ -42,7 +42,8 @@ def __init__( self, pool_size: int = DEFAULT_POOLSIZE, num_retries: int = DEFAULT_NUM_RETRIES, - request_timeout: int = DEFAULT_REQUEST_TIMEOUT, + request_timeout: int = defines.DEFAULT_GET_TIMEOUT_SECONDS, + post_timeout: float = defines.DEFAULT_POST_TIMEOUT_SECONDS, backoff_factor: float = DEFAULT_BACKOFF_FACTOR, session: Session = None, stream_session: Session = None, @@ -50,6 +51,7 @@ def __init__( self.pool_size: int = pool_size self.num_retries: int = num_retries self.request_timeout: int = request_timeout + self.post_timeout: float = post_timeout self.backoff_factor: float = backoff_factor # adding 504 to the tuple of statuses to retry @@ -134,7 +136,7 @@ def post(self, url: str, data: Dict[str, str] = None) -> Response: :raise: :exc:`ConnectionError ` """ try: - resp = self._session.post(url, data=data, timeout=self.request_timeout) + resp = self._session.post(url, data=data, timeout=self.post_timeout) except (RequestException, NewConnectionError) as err: raise ConnectionError(err) return Response(