1616import queue
1717import socket
1818import ssl
19- import sys
2019
2120import v3io .dataplane .request
2221import v3io .dataplane .response
2524
2625
2726class Transport (abstract .Transport ):
27+ _connection_timeout_seconds = 20
28+ _request_max_retries = 2
29+
2830 def __init__ (self , logger , endpoint = None , max_connections = None , timeout = None , verbosity = None ):
2931 super (Transport , self ).__init__ (logger , endpoint , max_connections , timeout , verbosity )
3032
@@ -36,24 +38,19 @@ def __init__(self, logger, endpoint=None, max_connections=None, timeout=None, ve
3638 # create the pool connection
3739 self ._create_connections (self .max_connections , self ._host , self ._ssl_context )
3840
39- # python 2 and 3 have different exceptions
40- if sys .version_info [0 ] >= 3 :
41- self ._wait_response_exceptions = (
42- http .client .RemoteDisconnected ,
43- ConnectionResetError ,
44- ConnectionRefusedError ,
45- http .client .ResponseNotReady ,
46- )
47- self ._send_request_exceptions = (
48- BrokenPipeError ,
49- http .client .CannotSendRequest ,
50- http .client .RemoteDisconnected ,
51- )
52- self ._get_status_and_headers = self ._get_status_and_headers_py3
53- else :
54- self ._wait_response_exceptions = (http .client .BadStatusLine , socket .error )
55- self ._send_request_exceptions = (http .client .CannotSendRequest , http .client .BadStatusLine )
56- self ._get_status_and_headers = self ._get_status_and_headers_py2
41+ self ._wait_response_exceptions = (
42+ http .client .RemoteDisconnected ,
43+ ConnectionResetError ,
44+ ConnectionRefusedError ,
45+ http .client .ResponseNotReady ,
46+ )
47+ self ._send_request_exceptions = (
48+ BrokenPipeError ,
49+ http .client .CannotSendRequest ,
50+ http .client .RemoteDisconnected ,
51+ socket .timeout ,
52+ )
53+ self ._get_status_and_headers = self ._get_status_and_headers_py3
5754
5855 def close (self ):
5956 # Ignore redundant calls to close
@@ -154,20 +151,27 @@ def _send_request_on_connection(self, request, connection):
154151 self .log (
155152 "Tx" , connection = connection , method = request .method , path = path , headers = request .headers , body = request .body
156153 )
154+
157155 starting_offset = 0
158156 is_body_seekable = request .body and hasattr (request .body , "seek" ) and hasattr (request .body , "tell" )
159157 if is_body_seekable :
160158 starting_offset = request .body .tell ()
161- try :
159+
160+ retries_left = self ._request_max_retries
161+ while True :
162162 try :
163163 connection .request (request .method , path , request .body , request .headers )
164+ break
164165 except self ._send_request_exceptions as e :
165166 self ._logger .debug_with (
166- "Disconnected while attempting to send. Recreating connection and retrying" ,
167+ f"Disconnected while attempting to send request – "
168+ f"{ retries_left } out of { self ._request_max_retries } retries left." ,
167169 e = type (e ),
168170 e_msg = e ,
169- connection = connection ,
170171 )
172+ if retries_left == 0 :
173+ raise
174+ retries_left -= 1
171175 connection .close ()
172176 if is_body_seekable :
173177 # If the first connection fails, the pointer of the body might move at the size
@@ -176,12 +180,11 @@ def _send_request_on_connection(self, request, connection):
176180 request .body .seek (starting_offset )
177181 connection = self ._create_connection (self ._host , self ._ssl_context )
178182 request .transport .connection_used = connection
179- connection .request (request .method , path , request .body , request .headers )
180- except BaseException as e :
181- self ._logger .error_with (
182- "Unhandled exception while sending request" , e = type (e ), e_msg = e , connection = connection
183- )
184- raise e
183+ except BaseException as e :
184+ self ._logger .error_with (
185+ "Unhandled exception while sending request" , e = type (e ), e_msg = e , connection = connection
186+ )
187+ raise e
185188
186189 return request
187190
@@ -192,9 +195,9 @@ def _create_connections(self, num_connections, host, ssl_context):
192195
193196 def _create_connection (self , host , ssl_context ):
194197 if ssl_context is None :
195- return http .client .HTTPConnection (host )
198+ return http .client .HTTPConnection (host , timeout = self . _connection_timeout_seconds )
196199
197- return http .client .HTTPSConnection (host , context = ssl_context )
200+ return http .client .HTTPSConnection (host , timeout = self . _connection_timeout_seconds , context = ssl_context )
198201
199202 def _parse_endpoint (self , endpoint ):
200203 if endpoint .startswith ("http://" ):
0 commit comments