3939from . import _session_retry_policy
4040from . import _timeout_failover_retry_policy
4141from . import exceptions
42+ from ._constants import _Constants
4243from .documents import _OperationType
4344from .exceptions import CosmosHttpResponseError
4445from .http_constants import HttpHeaders , StatusCodes , SubStatusCodes , ResourceType
4546from ._cosmos_http_logging_policy import _log_diagnostics_error
4647
47-
4848# pylint: disable=protected-access, disable=too-many-lines, disable=too-many-statements, disable=too-many-branches
4949# cspell:ignore PPAF,ppaf,ppcb
5050
@@ -65,6 +65,13 @@ def Execute(client, global_endpoint_manager, function, *args, **kwargs): # pylin
6565 :returns: the result of running the passed in function as a (result, headers) tuple
6666 :rtype: tuple of (dict, dict)
6767 """
68+ # Capture the client timeout and start time at the beginning
69+ timeout = kwargs .get ('timeout' )
70+ operation_start_time = kwargs .get (_Constants .OperationStartTime , time .time ())
71+
72+ # Track the last error for chaining
73+ last_error = None
74+
6875 pk_range_wrapper = None
6976 if args and (global_endpoint_manager .is_per_partition_automatic_failover_applicable (args [0 ]) or
7077 global_endpoint_manager .is_circuit_breaker_applicable (args [0 ])):
@@ -115,14 +122,25 @@ def Execute(client, global_endpoint_manager, function, *args, **kwargs): # pylin
115122 client , client ._container_properties_cache , None , * args )
116123
117124 while True :
118- client_timeout = kwargs .get ('timeout' )
119125 start_time = time .time ()
126+ # Check timeout before executing function
127+ if timeout :
128+ elapsed = time .time () - operation_start_time
129+ if elapsed >= timeout :
130+ raise exceptions .CosmosClientTimeoutError (error = last_error )
131+
120132 try :
121133 if args :
122134 result = ExecuteFunction (function , global_endpoint_manager , * args , ** kwargs )
123135 global_endpoint_manager .record_success (args [0 ], pk_range_wrapper )
124136 else :
125137 result = ExecuteFunction (function , * args , ** kwargs )
138+ # Check timeout after successful execution
139+ if timeout :
140+ elapsed = time .time () - operation_start_time
141+ if elapsed >= timeout :
142+ raise exceptions .CosmosClientTimeoutError (error = last_error )
143+
126144 if not client .last_response_headers :
127145 client .last_response_headers = {}
128146
@@ -163,6 +181,7 @@ def Execute(client, global_endpoint_manager, function, *args, **kwargs): # pylin
163181
164182 return result
165183 except exceptions .CosmosHttpResponseError as e :
184+ last_error = e
166185 if request :
167186 # update session token for relevant operations
168187 client ._UpdateSessionIfRequired (request .headers , {}, e .headers )
@@ -236,12 +255,13 @@ def Execute(client, global_endpoint_manager, function, *args, **kwargs): # pylin
236255 client .session .clear_session_token (client .last_response_headers )
237256 raise
238257
258+ # Now check timeout before retrying
259+ if timeout :
260+ elapsed = time .time () - operation_start_time
261+ if elapsed >= timeout :
262+ raise exceptions .CosmosClientTimeoutError (error = last_error )
239263 # Wait for retry_after_in_milliseconds time before the next retry
240264 time .sleep (retry_policy .retry_after_in_milliseconds / 1000.0 )
241- if client_timeout :
242- kwargs ['timeout' ] = client_timeout - (time .time () - start_time )
243- if kwargs ['timeout' ] <= 0 :
244- raise exceptions .CosmosClientTimeoutError ()
245265
246266 except ServiceRequestError as e :
247267 if request and _has_database_account_header (request .headers ):
@@ -270,6 +290,7 @@ def ExecuteFunction(function, *args, **kwargs):
270290 """
271291 return function (* args , ** kwargs )
272292
293+
273294def _has_read_retryable_headers (request_headers ):
274295 if _OperationType .IsReadOnlyOperation (request_headers .get (HttpHeaders .ThinClientProxyOperationType )):
275296 return True
@@ -345,6 +366,7 @@ def send(self, request):
345366 :raises ~azure.cosmos.exceptions.CosmosClientTimeoutError: Specified timeout exceeded.
346367 :raises ~azure.core.exceptions.ClientAuthenticationError: Authentication failed.
347368 """
369+
348370 absolute_timeout = request .context .options .pop ('timeout' , None )
349371 per_request_timeout = request .context .options .pop ('connection_timeout' , 0 )
350372 request_params = request .context .options .pop ('request_params' , None )
@@ -397,6 +419,7 @@ def send(self, request):
397419 if retry_active :
398420 self .sleep (retry_settings , request .context .transport )
399421 continue
422+
400423 raise err
401424 except CosmosHttpResponseError as err :
402425 raise err
0 commit comments