Page Summary
-
Display & Video 360 reports are not generated instantly and can take several minutes to over an hour.
-
To check if a report is finished, you need to poll its status using the
queries.reports.getmethod and check themetadata.status.statefield for "DONE" or "FAILED". -
Polling inefficiently can consume a lot of API request quota.
-
Using exponential backoff is recommended to limit retries and conserve quota when polling for report completion.
Display & Video 360 reports don't generate instantaneously. Display & Video 360 might take multiple minutes to over an hour to create a report file.
To determine if your query finished running, regularly retrieve the report using queries.reports.get
, then check if the resource's metadata.status.state
field has been updated to DONE
or FAILED
. This process is known as "polling".
An inefficient polling implementation checking on a long-running report consumes a lot of API request quota . To limit retries and conserve quota, use exponential backoff .
Here's how to poll a report using exponential backoff:
Java
//This example the following import. import com.google.api.client.util.ExponentialBackOff ; // The ID of the parent query. Long queryId = query - id ; // The ID of the running report. Long reportId = report - id ; // Minimum amount of time between polling requests. Defaults to 5 seconds. final int MIN_RETRY_INTERVAL_IN_MILLIS = 5_000 ; // Maximum amount of time between polling requests. Defaults to 5 minutes. final int MAX_RETRY_INTERVAL_IN_MILLIS = 5 * 60_000 ; // Maximum amount of time to spend polling. Defaults to 5 hours. final int MAX_RETRY_ELAPSED_TIME_IN_MILLIS = 5 * 60 * 60_000 ; // Configure reports.get request. Reports . Get reportGetRequest = service . queries (). reports (). get ( queryId , reportId ); // Get initial report object. Report report = reportGetRequest . execute (); // Configure exponential backoff for checking the status of our report. ExponentialBackOff backOff = new ExponentialBackOff . Builder () . setInitialIntervalMillis ( MIN_RETRY_INTERVAL_IN_MILLIS ) . setMaxIntervalMillis ( MAX_RETRY_INTERVAL_IN_MILLIS ) . setMaxElapsedTimeMillis ( MAX_RETRY_ELAPSED_TIME_IN_MILLIS ) . build (); // Poll report while it is running. while ( ! report . getMetadata (). getStatus (). getState (). equals ( "DONE" ) && ! report . getMetadata (). getStatus (). getState (). equals ( "FAILED" )) { long backoffMillis = backOff . nextBackOffMillis (); if ( backoffMillis == ExponentialBackOff . STOP ) { break ; } System . out . printf ( "Report %s still running, sleeping for %s seconds.%n" , reportId , backoffMillis / 1000 ); Thread . sleep ( backoffMillis ); // Get current status of operation. report = reportGetRequest . execute (); } // Print the result of the report generation. if ( report . getMetadata (). getStatus (). getState (). equals ( "DONE" )) { System . out . printf ( "Report %s was successfully generated.%n" , report . getKey (). getReportId ()); } else if ( report . getMetadata (). getStatus (). getState (). equals ( "FAILED" )) { System . out . printf ( "Report %s finished in error.%n" , report . getKey (). getReportId ()); } else { System . out . println ( "Report generation deadline exceeded." ); }
Python
# The ID of the parent query. query_id = query - id # The ID of the report. report_id = report - id # The following values control retry behavior while # the report is processing. # Minimum amount of time between polling requests. Defaults to 5 seconds. min_retry_interval = 5 # Maximum amount of time between polling requests. Defaults to 5 minutes. max_retry_interval = 5 * 60 # Maximum amount of time to spend polling. Defaults to 5 hours. max_retry_elapsed_time = 5 * 60 * 60 # Configure the queries.reports.get request. get_request = service . queries () . reports () . get ( queryId = query_id , reportId = report_id ) sleep = 0 # Poll report while it is running. start_time = time . time () while True : # Get current status of the report report = get_request . execute () # Print status if report is finished or deadline is exceeded. if report [ "metadata" ][ "status" ][ "state" ] == "DONE" : print ( f 'Report { report [ "key" ][ "reportId" ] } was successfully generated.' ) break elif report [ "metadata" ][ "status" ][ "state" ] == "FAILED" : print ( f 'Report { report [ "key" ][ "reportId" ] } finished in error.' ) break elif time . time () - start_time > max_retry_elapsed_time : print ( "Report generation deadline exceeded." ) break sleep = next_sleep_interval ( sleep ) print ( f 'Report { report [ "key" ][ "reportId" ] } still running, sleeping for ' f ' { sleep } seconds.' ) time . sleep ( sleep ) def next_sleep_interval ( previous_sleep_interval ): """Calculates the next sleep interval based on the previous.""" min_interval = previous_sleep_interval or min_retry_interval max_interval = previous_sleep_interval * 3 or min_retry_interval return min ( max_retry_interval , random . randint ( min_interval , max_interval ))
PHP
// The ID of the parent query. $queryId = query-id ; // The ID of the running report. $reportId = report-id ; // Minimum amount of time between polling requests. Defaults to 5 seconds. $minRetryInterval = 5; // Maximum amount of time between polling requests. Defaults to 5 minutes. $maxRetryInterval = 300; // Maximum amount of time to spend polling. Defaults to 5 hours. $maxRetryElapsedTime = 18000; $sleepInterval = 0; $startTime = time(); // Get initial report object. $report = $this->service->queries_reports->get($queryId, $reportId); // Regularly poll report status using exponential backoff. while ( $report->getMetadata()->getStatus()->getState() !== "DONE" && $report->getMetadata()->getStatus()->getState() !== "FAILED" ) { // If the operation has exceeded the set deadline, throw an exception. if (time() - $startTime > $maxRetryElapsedTime) { printf('SDF download task processing deadline exceeded\n'); break; } // Generate the next sleep interval using exponential backoff logic. $sleepInterval = min( $maxRetryInterval, rand( max($minRetryInterval, $sleepInterval), max($minRetryInterval, $sleepInterval * 3) ) ); // Sleep before retrieving the report again. printf( 'Report is %d still running, sleeping for %d seconds<br>', $reportId, $sleepInterval ); sleep($sleepInterval); // Retrieve the report. $report = $this->service->queries_reports->get($queryId, $reportId); } // Print the result of the report generation. if($report->getMetadata()->getStatus()->getState() == "DONE") { printf('Report %d was successfully generated.<br>', $reportId); } else if($report->getMetadata()->getStatus()->getState() == "FAILED") { printf('Report %d finished in error.<br>', $reportId); } else { print('Report generation deadline exceeded.<br>'); }

