googleads/google-ads-python

Keyword Historical Metric - RESOURCE_EXHAUSTED

NeerajG03 opened this issue · 3 comments

Describe the bug:

I am trying to use the KeywordPlanIdeaService and am running into the issue of RESOURCE_EXHAUSTED. This doesn't seem to be an issue always i run into this issue and there is no source for this error I have seen. The error seems to be random and not always pop up. It say retry after 30 seconds which i retiried even after one whole day and it throws this error. I retry after like 2 seconds and it works. I don't totally grasp why this might be happening and require some assistance.

Steps to Reproduce:

def generate_historical_metrics(client, customer_id,keywords):
    googleads_service = client.get_service("GoogleAdsService")
    keyword_plan_idea_service = client.get_service("KeywordPlanIdeaService")
    request = client.get_type("GenerateKeywordHistoricalMetricsRequest")
    request.customer_id = customer_id
    request.keywords.extend(keywords)
    request.geo_target_constants.append(
        googleads_service.geo_target_constant_path("2840")
    )
    request.keyword_plan_network = (
        client.enums.KeywordPlanNetworkEnum.GOOGLE_SEARCH
    )
    request.language = googleads_service.language_constant_path("1000")

    response = keyword_plan_idea_service.generate_keyword_historical_metrics(
        request=request
    )

    output = []
    for result in response.results:
        metrics = result.keyword_metrics
        newval = []
        for each in list(metrics.monthly_search_volumes):
            newval.append({"year":each.year,"month":each.month,"searches":each.monthly_searches})

        output.append({
            "keyword":result.text,
            "variants":str(result.close_variants) if result.close_variants else 'None',
            "searches":metrics.avg_monthly_searches,
            "competition_level":"Low" if metrics.competition == 2 else "Medium" if metrics.competition==3 else "High" if metrics.competition==4 else "Level Unknown",
            "competition_index" : metrics.competition_index,
            "lowest_bid": metrics.low_top_of_page_bid_micros,
            "highest_bid": metrics.high_top_of_page_bid_micros,
            "history":newval,
            "growing":is_trajectory_upward(newval)
                    
        })
        print(output[-1])

I run the above code like so:

googleads_client = GoogleAdsClient.load_from_storage(path="GoogleAPI/google-ads.yaml",version="v15")
customer_id = 'xxxxxxxxx'
keywords = ["word1","word2,"word3"]
generate_historical_metrics(googleads_client, customer_id,keywords)

Expected behavior:

Print the output one after the other.
which it does sometimes:
When it works:

Ouput:
{'keyword': 'word1', 'variants': 'None', 'searches': 210, 'competition_level': 'Low', 'competition_index': 4, 'lowest_bid': 0, 'highest_bid': 0, 'history': [{'year': 2023, 'month': 3, 'searches': 110}, {'year': 2023, 'month': 4, 'searches': 1000}, {'year': 2023, 'month': 5, 'searches': 90}, {'year': 2023, 'month': 6, 'searches': 90}, {'year': 2023, 'month': 7, 'searches': 90}, {'year': 2023, 'month': 8, 'searches': 90}, {'year': 2023, 'month': 9, 'searches': 110}, {'year': 2023, 'month': 10, 'searches': 140}, {'year': 2023, 'month': 11, 'searches': 140}, {'year': 2023, 'month': 12, 'searches': 90}, {'year': 2023, 'month': 13, 'searches': 110}, {'year': 2024, 'month': 2, 'searches': 110}], 'growing': False}
{'keyword': 'word2', 'variants': 'None', 'searches': 4400, 'competition_level': 'Low', 'competition_index': 2, 'lowest_bid': 29970407, 'highest_bid': 581105000, 'history': [{'year': 2023, 'month': 3, 'searches': 4400}, {'year': 2023, 'month': 4, 'searches': 5400}, {'year': 2023, 'month': 5, 'searches': 3600}, {'year': 2023, 'month': 6, 'searches': 3600}, {'year': 2023, 'month': 7, 'searches': 3600}, {'year': 2023, 'month': 8, 'searches': 3600}, {'year': 2023, 'month': 9, 'searches': 3600}, {'year': 2023, 'month': 10, 'searches': 4400}, {'year': 2023, 'month': 11, 'searches': 4400}, {'year': 2023, 'month': 12, 'searches': 4400}, {'year': 2023, 'month': 13, 'searches': 5400}, {'year': 2024, 'month': 2, 'searches': 5400}], 'growing': True}

When it throws error:

Output:
Request made: ClientCustomerId: 5959491719, Host: googleads.googleapis.com, Method: /google.ads.googleads.v15.services.KeywordPlanIdeaService/GenerateKeywordHistoricalMetrics, RequestId: XjjJbCCSYYPEz2vJ3bWI_A, IsFault: True, FaultMessage: Resource has been exhausted (e.g. check quota).
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/google/api_core/grpc_helpers.py", line 79, in error_remapped_callable
    return callable_(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_interceptor.py", line 277, in __call__
    response, ignored_call = self._with_call(
                             ^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_interceptor.py", line 332, in _with_call
    return call.result(), call
           ^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_channel.py", line 437, in result
    raise self
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_interceptor.py", line 315, in continuation
    response, call = self._thunk(new_method).with_call(
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_interceptor.py", line 343, in with_call
    return self._with_call(
           ^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_interceptor.py", line 332, in _with_call
    return call.result(), call
           ^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_channel.py", line 437, in result
    raise self
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_interceptor.py", line 315, in continuation
    response, call = self._thunk(new_method).with_call(
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_interceptor.py", line 343, in with_call
    return self._with_call(
           ^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_interceptor.py", line 329, in _with_call
    call = self._interceptor.intercept_unary_unary(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/google/ads/googleads/interceptors/exception_interceptor.py", line 99, in intercept_unary_unary
    self._handle_grpc_failure(response)
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/google/ads/googleads/interceptors/exception_interceptor.py", line 71, in _handle_grpc_failure
    raise self._get_error_from_response(response)
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_interceptor.py", line 315, in continuation
    response, call = self._thunk(new_method).with_call(
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_channel.py", line 1177, in with_call
    return _end_unary_response_blocking(state, call, True, None)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_channel.py", line 1003, in _end_unary_response_blocking
    raise _InactiveRpcError(state)  # pytype: disable=not-instantiable
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with:
        status = StatusCode.RESOURCE_EXHAUSTED
        details = "Resource has been exhausted (e.g. check quota)."
        debug_error_string = "UNKNOWN:Error received from peer ipv6:%5B2404:6800:4007:818::200a%5D:443 {grpc_message:"Resource has been exhausted (e.g. check quota).", grpc_status:8, created_time:"2024-02-17T20:06:36.312932+05:30"}"
>

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/ng/Documents/Github/python-api/GoogleAPI/local-test-file2.py", line 74, in <module>
    generate_historical_metrics(googleads_client, customer_id,keywords)
  File "/Users/ng/Documents/Github/python-api/GoogleAPI/local-test-file2.py", line 36, in generate_historical_metrics
    response = keyword_plan_idea_service.generate_keyword_historical_metrics(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/google/ads/googleads/v15/services/services/keyword_plan_idea_service/client.py", line 539, in generate_keyword_historical_metrics
    response = rpc(
               ^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/google/api_core/gapic_v1/method.py", line 131, in __call__
    return wrapped_func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/google/api_core/grpc_helpers.py", line 81, in error_remapped_callable
    raise exceptions.from_grpc_error(exc) from exc
google.api_core.exceptions.ResourceExhausted: 429 Resource has been exhausted (e.g. check quota). [type_url: "type.googleapis.com/google.ads.googleads.v15.errors.GoogleAdsFailure"
value: "\n-\n\002X\002\022\'Too many requests. Retry in 30 seconds.\022\026XjjJbCCSYYPEz2vJ3bWI_A"]

Client library version and API version:

Client library version:
Google Ads API version:

Request/Response Logs:

[2024-02-17 20:10:43,678 - INFO] Request
-------
Method: /google.ads.googleads.v15.services.KeywordPlanIdeaService/GenerateKeywordHistoricalMetrics
Host: googleads.googleapis.com
Headers: {
  "developer-token": "REDACTED",
  "login-customer-id": "xxxxxxxxx",
  "x-goog-api-client": "gl-python/3.11.7 grpc/1.60.1 gax/2.16.2 gccl/23.0.0 pb/4.25.2",
  "x-goog-request-params": "customer_id=xxxxxxxx"
}
Request: customer_id: "xxxxxxxxx"
keywords: "ai analytics"
keywords: "marketing"
language: "languageConstants/1000"
geo_target_constants: "geoTargetConstants/2840"
keyword_plan_network: GOOGLE_SEARCH


Response
-------
Headers: {
  "google.ads.googleads.v15.errors.googleadsfailure-bin": "\n-\n\u0002X\u0002\u0012'Too many requests. Retry in 30 seconds.\u0012\u0016N5ryRsfeFjxtVKmARHpwCQ",
  "grpc-status-details-bin": "\b\b\u0012/Resource has been exhausted (e.g. check quota).\u001a\u0001\nDtype.googleapis.com/google.ads.googleads.v15.errors.GoogleAdsFailure\u0012G\n-\n\u0002X\u0002\u0012'Too many requests. Retry in 30 seconds.\u0012\u0016N5ryRsfeFjxtVKmARHpwCQ",
  "request-id": "N5ryRsfeFjxtVKmARHpwCQ"
}
Fault: {}

[2024-02-17 20:10:43,679 - WARNING] Request made: ClientCustomerId: xxxxxxxxx, Host: googleads.googleapis.com, Method: /google.ads.googleads.v15.services.KeywordPlanIdeaService/GenerateKeywordHistoricalMetrics, RequestId: N5ryRsfeFjxtVKmARHpwCQ, IsFault: True, FaultMessage: Resource has been exhausted (e.g. check quota).
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/google/api_core/grpc_helpers.py", line 79, in error_remapped_callable
    return callable_(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_interceptor.py", line 277, in __call__
    response, ignored_call = self._with_call(
                             ^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_interceptor.py", line 332, in _with_call
    return call.result(), call
           ^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_channel.py", line 437, in result
    raise self
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_interceptor.py", line 315, in continuation
    response, call = self._thunk(new_method).with_call(
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_interceptor.py", line 343, in with_call
    return self._with_call(
           ^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_interceptor.py", line 332, in _with_call
    return call.result(), call
           ^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_channel.py", line 437, in result
    raise self
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_interceptor.py", line 315, in continuation
    response, call = self._thunk(new_method).with_call(
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_interceptor.py", line 343, in with_call
    return self._with_call(
           ^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_interceptor.py", line 329, in _with_call
    call = self._interceptor.intercept_unary_unary(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/google/ads/googleads/interceptors/exception_interceptor.py", line 99, in intercept_unary_unary
    self._handle_grpc_failure(response)
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/google/ads/googleads/interceptors/exception_interceptor.py", line 71, in _handle_grpc_failure
    raise self._get_error_from_response(response)
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_interceptor.py", line 315, in continuation
    response, call = self._thunk(new_method).with_call(
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_channel.py", line 1177, in with_call
    return _end_unary_response_blocking(state, call, True, None)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/grpc/_channel.py", line 1003, in _end_unary_response_blocking
    raise _InactiveRpcError(state)  # pytype: disable=not-instantiable
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with:
	status = StatusCode.RESOURCE_EXHAUSTED
	details = "Resource has been exhausted (e.g. check quota)."
	debug_error_string = "UNKNOWN:Error received from peer ipv6:%5B2404:6800:4007:816::200a%5D:443 {created_time:"2024-02-17T20:10:43.674219+05:30", grpc_status:8, grpc_message:"Resource has been exhausted (e.g. check quota)."}"
>

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/neerajgopalakrishnan/Documents/Github/python-api/GoogleAPI/local-test-file2.py", line 77, in <module>
    generate_historical_metrics(googleads_client, customer_id,keywords)
  File "/Users/neerajgopalakrishnan/Documents/Github/python-api/GoogleAPI/local-test-file2.py", line 39, in generate_historical_metrics
    response = keyword_plan_idea_service.generate_keyword_historical_metrics(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/google/ads/googleads/v15/services/services/keyword_plan_idea_service/client.py", line 539, in generate_keyword_historical_metrics
    response = rpc(
               ^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/google/api_core/gapic_v1/method.py", line 131, in __call__
    return wrapped_func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/google/api_core/grpc_helpers.py", line 81, in error_remapped_callable
    raise exceptions.from_grpc_error(exc) from exc
google.api_core.exceptions.ResourceExhausted: 429 Resource has been exhausted (e.g. check quota). [type_url: "type.googleapis.com/google.ads.googleads.v15.errors.GoogleAdsFailure"
value: "\n-\n\002X\002\022\'Too many requests. Retry in 30 seconds.\022\026N5ryRsfeFjxtVKmARHpwCQ"
]

Anything else we should know about your project / environment:
I don't think it is related to environment as it works sometimes. I'm just knowledgable about why the quota is being crossed

This might be a stupid issue so feel free to ask me questions and i an ready to answer. I just am unable to figure out for the life of me why this is happening.

You are limited to approximately 1 request per second, and the scripts often checks if the quota is passed each 5 or 30 seconds.
Using a time.sleep(1) between each request will fix the issue.

Furthermore, you have a 15k request a day limit on the basic access and it is calculed based on the last 24 hours.

Hope this helps,

@NeerajG03 let me know if the suggestions from @MaxBarbet help. If not, I recommend following the support steps on this page to resolve the issue, as it doesn't look to be an issue with this library.