Page Summary
-
By default, the client library for Python delegates timeout behavior to the server, which is suitable for most use cases.
-
Client-side timeouts can be specified for both streaming and unary calls in the Python client library by adding an extra parameter.
-
While you can set a client-side timeout of 2 hours or more, very long-running requests might still time out on the API side with a
DEADLINE_EXCEEDEDerror. -
For extremely long requests that time out, splitting the query into chunks and executing them in parallel can prevent failure and the need to restart the request.
-
The
GoogleAdsService.SearchStreammethod uses streaming calls, and timeout overrides are added as atimeoutparameter. -
Most Google Ads API methods use unary calls, and timeout overrides are configured using the
retryparameter with a specifieddeadline.
The client library for Python doesn't specify any default timeouts, nor are any defaults specified at the gRPC transport layer. By default, the client library for Python delegates timeout behavior to the server.
This default works for most use cases. However, if you need to specify a
client-side timeout, the Python client library supports per-request timeout
overrides (specified in seconds as an int or float) for both streaming
and unary calls. Client-wide default timeouts cannot be configured in
google-ads.yaml.
You can set a custom timeout to 2 hours (7,200 seconds) or more, but the API
might still time out extremely long-running requests and return a
DEADLINE_EXCEEDED gRPC status error. If this becomes an
issue, split the query into smaller chunks and execute them in parallel; this
avoids the situation where a long-running request fails and the only way to
recover is to restart the request from the beginning.
Stream call timeouts
The only Google Ads API service method that uses a response stream is
GoogleAdsService.SearchStream.
To override the default timeout, pass the timeout parameter (in seconds) when
calling the method:
def make_server_streaming_call( client: GoogleAdsClient, customer_id: str ) -> None: """Makes a server streaming call using a custom client timeout. Args: client: An initialized GoogleAds client. customer_id: The str Google Ads customer ID. """ ga_service: GoogleAdsServiceClient = client.get_service("GoogleAdsService") campaign_ids: List[str] = [] try: search_request: SearchGoogleAdsStreamRequest = client.get_type( "SearchGoogleAdsStreamRequest" ) search_request.customer_id = customer_id search_request.query = _QUERY stream: Iterator[SearchGoogleAdsStreamResponse] = ( ga_service.search_stream( request=search_request, # When making any request, an optional "timeout" parameter can be # provided to specify a client-side response deadline in seconds. # If not set, then no timeout will be enforced by the client and # the channel will remain open until the response is completed or # severed, either manually or by the server. timeout=_CLIENT_TIMEOUT_SECONDS, ) ) batch: SearchGoogleAdsStreamResponse for batch in stream: row: GoogleAdsRow for row in batch.results: campaign_ids.append(row.campaign.id) print("The server streaming call completed before the timeout.") except DeadlineExceeded: print("The server streaming call did not complete before the timeout.") sys.exit(1) except GoogleAdsException as ex: print( f"Request with ID '{ex.request_id}' failed with status " f"'{ex.error.code().name}' and includes the following errors:" ) for error in ex.failure.errors: print(f"\tError with message '{error.message}'.") if error.location: for field_path_element in error.location.field_path_elements: print(f"\t\tOn field: {field_path_element.field_name}") sys.exit(1) print(f"Total # of campaign IDs retrieved: {len(campaign_ids)}")
Unary call timeouts
Most of the Google Ads API service methods use unary calls; typical examples are
GoogleAdsService.Search and
GoogleAdsService.Mutate.
To override the default deadline and retry settings for a unary call, pass a
google.api_core.retry.Retry object using the retry parameter (or pass
timeout in seconds for a single-attempt timeout):
def make_unary_call(client: GoogleAdsClient, customer_id: str) -> None: """Makes a unary call using a custom client timeout. Args: client: An initialized GoogleAds client. customer_id: The Google Ads customer ID. """ ga_service: GoogleAdsServiceClient = client.get_service("GoogleAdsService") campaign_ids: List[str] = [] try: search_request: SearchGoogleAdsRequest = client.get_type( "SearchGoogleAdsRequest" ) search_request.customer_id = customer_id search_request.query = _QUERY results: Iterator[GoogleAdsRow] = ga_service.search( request=search_request, # When making any request, an optional "retry" parameter can be # provided to specify its retry behavior. Complete information about # these settings can be found here: # https://googleapis.dev/python/google-api-core/latest/retry.html retry=Retry( # Sets the maximum accumulative timeout of the call; it # includes all tries. deadline=_CLIENT_TIMEOUT_SECONDS, # Sets the timeout that is used for the first try to one tenth # of the maximum accumulative timeout of the call. # Note: This overrides the default value and can lead to # RequestError.RPC_DEADLINE_TOO_SHORT errors when too small. We # recommend changing the value only if necessary. initial=_CLIENT_TIMEOUT_SECONDS / 10, # Sets the maximum timeout that can be used for any given try # to one fifth of the maximum accumulative timeout of the call # (two times greater than the timeout that is needed for the # first try). maximum=_CLIENT_TIMEOUT_SECONDS / 5, ), ) row: GoogleAdsRow for row in results: campaign_ids.append(row.campaign.id) print("The unary call completed before the timeout.") except DeadlineExceeded: print("The unary call did not complete before the timeout.") sys.exit(1) except GoogleAdsException as ex: print( f"Request with ID '{ex.request_id}' failed with status " f"'{ex.error.code().name}' and includes the following errors:" ) for error in ex.failure.errors: print(f"\tError with message '{error.message}'.") if error.location: for field_path_element in error.location.field_path_elements: print(f"\t\tOn field: {field_path_element.field_name}") sys.exit(1) print(f"Total # of campaign IDs retrieved: {len(campaign_ids)}")