1- __all__ = ["HTTPClient" , "DefaultHTTPClient" ]
1+ __all__ = ["HTTPClient" , "DefaultHTTPClient" , "DEFAULT_REQUEST_TIMEOUT" ]
22
3+ import typing
34from abc import ABC , abstractmethod
4- from typing import MutableMapping , Optional , Tuple , Union
5+ from typing import Any , MutableMapping , Optional , Tuple , Union
56
67from requests import Session
7- from requests .adapters import HTTPAdapter
8+ from requests .adapters import DEFAULT_POOLBLOCK , DEFAULT_POOLSIZE , HTTPAdapter
89from requests_toolbelt import MultipartEncoder
10+ from urllib3 .poolmanager import PoolManager
911from urllib3 .util .retry import Retry
1012
1113from arango .response import Response
1214from arango .typings import Headers
1315
16+ DEFAULT_REQUEST_TIMEOUT = 60
17+
1418
1519class HTTPClient (ABC ): # pragma: no cover
1620 """Abstract base class for HTTP clients."""
@@ -63,12 +67,92 @@ def send_request(
6367 raise NotImplementedError
6468
6569
66- class DefaultHTTPClient (HTTPClient ):
67- """Default HTTP client implementation."""
70+ class DefaultHTTPAdapter (HTTPAdapter ):
71+ """Default transport adapter implementation
72+
73+ :param connection_timeout: Socket timeout in seconds for each individual connection.
74+ :type connection_timeout: int | float
75+ :param pool_connections: The number of urllib3 connection pools to cache.
76+ :type pool_connections: int
77+ :param pool_maxsize: The maximum number of connections to save in the pool.
78+ :type pool_maxsize: int
79+ :param pool_timeout: If set, then the pool will be set to block=True,
80+ and requests will block for pool_timeout seconds and raise
81+ EmptyPoolError if no connection is available within the time period.
82+ :type pool_timeout: int | float | None
83+ :param kwargs: Additional keyword arguments passed to the HTTPAdapter constructor.
84+ :type kwargs: Any
85+ """
86+
87+ def __init__ (
88+ self ,
89+ connection_timeout : Union [int , float ] = DEFAULT_REQUEST_TIMEOUT ,
90+ pool_connections : int = DEFAULT_POOLSIZE ,
91+ pool_maxsize : int = DEFAULT_POOLSIZE ,
92+ pool_timeout : Union [int , float , None ] = None ,
93+ ** kwargs : Any
94+ ) -> None :
95+ self ._connection_timeout = connection_timeout
96+ self ._pool_timeout = pool_timeout
97+ super ().__init__ (
98+ pool_connections = pool_connections , pool_maxsize = pool_maxsize , ** kwargs
99+ )
100+
101+ @typing .no_type_check
102+ def init_poolmanager (
103+ self , connections , maxsize , block = DEFAULT_POOLBLOCK , ** pool_kwargs
104+ ) -> None :
105+ kwargs = pool_kwargs
106+ kwargs .update (
107+ dict (
108+ num_pools = connections ,
109+ maxsize = maxsize ,
110+ strict = True ,
111+ timeout = self ._connection_timeout ,
112+ )
113+ )
114+ if self ._pool_timeout is not None :
115+ kwargs ["block" ] = True
116+ kwargs ["timeout" ] = self ._pool_timeout
117+ else :
118+ kwargs ["block" ] = False
119+ self .poolmanager = PoolManager (** kwargs )
68120
69- REQUEST_TIMEOUT = 60
70- RETRY_ATTEMPTS = 3
71- BACKOFF_FACTOR = 1
121+
122+ class DefaultHTTPClient (HTTPClient ):
123+ """Default HTTP client implementation.
124+
125+ :param request_timeout: Timeout in seconds for each individual connection.
126+ :type request_timeout: int | float
127+ :param retry_attempts: Number of retry attempts.
128+ :type retry_attempts: int
129+ :param backoff_factor: Backoff factor for retry attempts.
130+ :type backoff_factor: float
131+ :param pool_connections: The number of urllib3 connection pools to cache.
132+ :type pool_connections: int
133+ :param pool_maxsize: The maximum number of connections to save in the pool.
134+ :type pool_maxsize: int
135+ :param pool_timeout: If set, then the pool will be set to block=True,
136+ and requests will block for pool_timeout seconds and raise
137+ EmptyPoolError if no connection is available within the time period.
138+ :type pool_timeout: int | float | None
139+ """
140+
141+ def __init__ (
142+ self ,
143+ request_timeout : Union [int , float ] = DEFAULT_REQUEST_TIMEOUT ,
144+ retry_attempts : int = 3 ,
145+ backoff_factor : float = 1.0 ,
146+ pool_connections : int = 10 ,
147+ pool_maxsize : int = 10 ,
148+ pool_timeout : Union [int , float , None ] = None ,
149+ ) -> None :
150+ self .request_timeout = request_timeout
151+ self ._retry_attempts = retry_attempts
152+ self ._backoff_factor = backoff_factor
153+ self ._pool_connections = pool_connections
154+ self ._pool_maxsize = pool_maxsize
155+ self ._pool_timeout = pool_timeout
72156
73157 def create_session (self , host : str ) -> Session :
74158 """Create and return a new session/connection.
@@ -79,12 +163,18 @@ def create_session(self, host: str) -> Session:
79163 :rtype: requests.Session
80164 """
81165 retry_strategy = Retry (
82- total = self .RETRY_ATTEMPTS ,
83- backoff_factor = self .BACKOFF_FACTOR ,
166+ total = self ._retry_attempts ,
167+ backoff_factor = self ._backoff_factor ,
84168 status_forcelist = [429 , 500 , 502 , 503 , 504 ],
85169 allowed_methods = ["HEAD" , "GET" , "OPTIONS" ],
86170 )
87- http_adapter = HTTPAdapter (max_retries = retry_strategy )
171+ http_adapter = DefaultHTTPAdapter (
172+ connection_timeout = self .request_timeout ,
173+ pool_connections = self ._pool_connections ,
174+ pool_maxsize = self ._pool_maxsize ,
175+ pool_timeout = self ._pool_timeout ,
176+ max_retries = retry_strategy ,
177+ )
88178
89179 session = Session ()
90180 session .mount ("https://" , http_adapter )
@@ -128,7 +218,7 @@ def send_request(
128218 data = data ,
129219 headers = headers ,
130220 auth = auth ,
131- timeout = self .REQUEST_TIMEOUT ,
221+ timeout = self .request_timeout ,
132222 )
133223 return Response (
134224 method = method ,
0 commit comments