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>'); }