Iteradores de streaming

O método search_stream retorna um iterador de objetos SearchGoogleAdsStreamResponse.

É possível iterar cada GoogleAdsRow no campo results de cada resposta, conforme mostrado neste exemplo de código.

def main(client: GoogleAdsClient, customer_id: str) -> None:
    ga_service: GoogleAdsServiceClient = client.get_service("GoogleAdsService")

    query: str = """
        SELECT
          campaign.id,
          campaign.name
        FROM campaign
        ORDER BY campaign.id"""

    # Issues a search request using streaming.
    stream: Iterator[SearchGoogleAdsStreamResponse] = ga_service.search_stream(
        customer_id=customer_id, query=query
    )

    for batch in stream:
        rows: List[GoogleAdsRow] = batch.results
        for row in rows:
            print(
                f"Campaign with ID {row.campaign.id} and name "
                f'"{row.campaign.name}" was found.'
            )
      

A estrutura de cada GoogleAdsRow é determinada pelos campos selecionados na consulta da linguagem de consulta do Google Ads (GAQL). Para mais detalhes sobre a estrutura da resposta, consulte a Linguagem de consulta do Google Ads.

Ao chamar GoogleAdsService.search_stream, um iterador de resposta de streaming é retornado. Esse iterador precisa permanecer no mesmo escopo do cliente GoogleAdsService durante o uso para evitar fluxos interrompidos ou falhas de segmentação. Isso ocorre porque o objeto gRPC Channel é coletado como lixo quando o objeto GoogleAdsService aberto sai do escopo. Se o objeto GoogleAdsService não estiver mais no escopo quando a iteração ocorrer no resultado de search_stream, o objeto Channel poderá já ter sido destruído, causando um comportamento indefinido quando o iterador tentar recuperar o próximo valor.

O código a seguir demonstra o uso incorreto de iteradores de streaming:

def stream_response(client, customer_id, query):
    return client.get_service("GoogleAdsService", version="v24").search_stream(customer_id, query=query)

def main(client, customer_id):
    query = "SELECT campaign.name FROM campaign LIMIT 10"
    response = stream_response(client, customer_id, query=query)
    # Access the iterator in a different scope from where the service object was created.
    try:
        for batch in response:
            # Iterate through response, expect undefined behavior.

Neste código, o objeto GoogleAdsService é criado em um escopo diferente de onde o iterador é acessado. Como resultado, o objeto Channel pode ser destruído antes que o iterador consuma toda a resposta.

Em vez disso, o iterador de streaming precisa permanecer no mesmo escopo do cliente GoogleAdsService enquanto estiver sendo usado:

def main(client, customer_id):
    ga_service = client.get_service("GoogleAdsService", version="v24")
    query = "SELECT campaign.name FROM campaign LIMIT 10"
    response = ga_service.search_stream(customer_id=customer_id, query=query)
    # Access the iterator in the same scope as where the service object was created.
    try:
        for batch in response:
            # Successfully iterate through response.