Page Summary
-
The
GoogleAdsService.search_streammethod returns a streaming response iterator. -
The iterator should stay in the same scope as the
GoogleAdsServiceclient to prevent broken streams or segmentation faults. -
If the
GoogleAdsServiceobject goes out of scope before the iterator is used, the underlying gRPCChannelobject may be garbage-collected, leading to undefined behavior. -
Accessing the iterator in a different scope than where the service object was created is incorrect usage.
-
The correct approach is to keep the streaming iterator in the same scope as the
GoogleAdsServiceclient while it is being used.
The search_stream
method returns an iterator of SearchGoogleAdsStreamResponse
objects.
You can iterate through each GoogleAdsRow
in each response's results
field as shown in this code example.
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.' )
The structure of each GoogleAdsRow
is determined by the
fields you select in your Google Ads Query Language (GAQL) query. For more
details about the response structure, see Google Ads Query Language
.
When calling GoogleAdsService.search_stream
,
a streaming response iterator is returned. This iterator should remain in the
same scope as the GoogleAdsService
client while being used in order to avoid
broken streams or segmentation faults. This is because the gRPC Channel
object
is garbage-collected once the open GoogleAdsService
object goes out of scope.
If the GoogleAdsService
object is no longer in scope by the time the iteration
occurs on the result of search_stream
, the Channel
object may already be
destroyed, causing undefined behavior when the iterator attempts to retrieve the
next value.
The following code demonstrates incorrect usage of streaming iterators:
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.
In this code, the GoogleAdsService
object is created within a different
scope from where the iterator is accessed. As a result, the Channel
object may
be destroyed before the iterator consumes the entire response.
Instead, the streaming iterator should remain in the same scope as the GoogleAdsService
client for as long as it is being used:
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.

