Poll report status
Stay organized with collections
Save and categorize content based on your preferences.
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>');
}
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License
, and code samples are licensed under the Apache 2.0 License
. For details, see the Google Developers Site Policies
. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2025-08-28 UTC.
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2025-08-28 UTC."],[[["\u003cp\u003eDisplay & Video 360 reports are not generated instantly and can take several minutes to over an hour to complete.\u003c/p\u003e\n"],["\u003cp\u003eYou need to periodically check the report status using the \u003ccode\u003equeries.reports.get\u003c/code\u003e method and the \u003ccode\u003emetadata.status.state\u003c/code\u003e field to see if it's 'DONE' or 'FAILED'.\u003c/p\u003e\n"],["\u003cp\u003eTo avoid excessive API requests and conserve quota, implement exponential backoff when polling for report status.\u003c/p\u003e\n"],["\u003cp\u003eThe provided code samples (Java, Python, PHP) demonstrate how to poll report status with exponential backoff.\u003c/p\u003e\n"]]],[],null,["# Poll report status\n\nDisplay \\& Video 360 reports don't generate instantaneously. Display \\& Video 360 might\ntake multiple minutes to over an hour to create a report file.\n\nTo determine if your query finished running, regularly retrieve the report using\n[`queries.reports.get`](/bid-manager/reference/rest/current/queries.reports/get), then check if the resource's\n[`metadata.status.state`](/bid-manager/reference/rest/current/queries.reports#ReportStatus.FIELDS.state) field has been updated to `DONE` or\n`FAILED`. This process is known as \"polling\".\n\nAn inefficient polling implementation checking on a long-running report consumes\na lot of [API request quota](/bid-manager/quotas). To limit retries and conserve quota,\nuse [exponential backoff](/bid-manager/guides/general/best-practices#exponential_backoff).\n\nHere's how to poll a report using exponential backoff: \n\n### Java\n\n```java\n//This example the following import.\nimport com.google.api.client.util.ExponentialBackOff;\n\n// The ID of the parent query.\nLong queryId = query-id;\n\n// The ID of the running report.\nLong reportId = report-id;\n\n// Minimum amount of time between polling requests. Defaults to 5 seconds.\nfinal int MIN_RETRY_INTERVAL_IN_MILLIS = 5_000;\n\n// Maximum amount of time between polling requests. Defaults to 5 minutes.\nfinal int MAX_RETRY_INTERVAL_IN_MILLIS = 5 * 60_000;\n\n// Maximum amount of time to spend polling. Defaults to 5 hours.\nfinal int MAX_RETRY_ELAPSED_TIME_IN_MILLIS = 5 * 60 * 60_000;\n\n// Configure reports.get request.\nReports.Get reportGetRequest =\n service.queries().reports().get(queryId, reportId);\n\n// Get initial report object.\nReport report = reportGetRequest.execute();\n\n// Configure exponential backoff for checking the status of our report.\nExponentialBackOff backOff =\n new ExponentialBackOff.Builder()\n .setInitialIntervalMillis(MIN_RETRY_INTERVAL_IN_MILLIS)\n .setMaxIntervalMillis(MAX_RETRY_INTERVAL_IN_MILLIS)\n .setMaxElapsedTimeMillis(MAX_RETRY_ELAPSED_TIME_IN_MILLIS)\n .build();\n\n// Poll report while it is running.\nwhile (!report.getMetadata().getStatus().getState().equals(\"DONE\")\n && !report.getMetadata().getStatus().getState().equals(\"FAILED\")) {\n long backoffMillis = backOff.nextBackOffMillis();\n if (backoffMillis == ExponentialBackOff.STOP) {\n break;\n }\n System.out.printf(\n \"Report %s still running, sleeping for %s seconds.%n\",\n reportId,\n backoffMillis / 1000);\n Thread.sleep(backoffMillis);\n\n // Get current status of operation.\n report = reportGetRequest.execute();\n}\n\n// Print the result of the report generation.\nif (report.getMetadata().getStatus().getState().equals(\"DONE\")) {\n System.out.printf(\n \"Report %s was successfully generated.%n\",\n report.getKey().getReportId());\n} else if (report.getMetadata().getStatus().getState().equals(\"FAILED\")) {\n System.out.printf(\n \"Report %s finished in error.%n\",\n report.getKey().getReportId());\n} else {\n System.out.println(\"Report generation deadline exceeded.\");\n}\n```\n\n### Python\n\n```python\n# The ID of the parent query.\nquery_id = query-id\n\n# The ID of the report.\nreport_id = report-id\n\n# The following values control retry behavior while\n# the report is processing.\n# Minimum amount of time between polling requests. Defaults to 5 seconds.\nmin_retry_interval = 5\n# Maximum amount of time between polling requests. Defaults to 5 minutes.\nmax_retry_interval = 5 * 60\n# Maximum amount of time to spend polling. Defaults to 5 hours.\nmax_retry_elapsed_time = 5 * 60 * 60\n\n# Configure the queries.reports.get request.\nget_request = service.queries().reports().get(\n queryId=query_id,reportId=report_id)\n\nsleep = 0\n\n# Poll report while it is running.\nstart_time = time.time()\nwhile True:\n # Get current status of the report\n report = get_request.execute()\n\n # Print status if report is finished or deadline is exceeded.\n if report[\"metadata\"][\"status\"][\"state\"] == \"DONE\":\n print(f'Report {report[\"key\"][\"reportId\"]} was successfully generated.')\n break\n elif report[\"metadata\"][\"status\"][\"state\"] == \"FAILED\":\n print(f'Report {report[\"key\"][\"reportId\"]} finished in error.')\n break\n elif time.time() - start_time \u003e max_retry_elapsed_time:\n print(\"Report generation deadline exceeded.\")\n break\n\n sleep = next_sleep_interval(sleep)\n print(\n f'Report {report[\"key\"][\"reportId\"]} still running, sleeping for '\n f'{sleep} seconds.')\n time.sleep(sleep)\n\ndef next_sleep_interval(previous_sleep_interval):\n \"\"\"Calculates the next sleep interval based on the previous.\"\"\"\n min_interval = previous_sleep_interval or min_retry_interval\n max_interval = previous_sleep_interval * 3 or min_retry_interval\n return min(\n max_retry_interval, random.randint(min_interval, max_interval))\n```\n\n### PHP\n\n```php\n// The ID of the parent query.\n$queryId = \u003cvar translate=\"no\"\u003equery-id\u003c/var\u003e;\n\n// The ID of the running report.\n$reportId = \u003cvar translate=\"no\"\u003ereport-id\u003c/var\u003e;\n\n// Minimum amount of time between polling requests. Defaults to 5 seconds.\n$minRetryInterval = 5;\n// Maximum amount of time between polling requests. Defaults to 5 minutes.\n$maxRetryInterval = 300;\n// Maximum amount of time to spend polling. Defaults to 5 hours.\n$maxRetryElapsedTime = 18000;\n\n$sleepInterval = 0;\n$startTime = time();\n\n// Get initial report object.\n$report = $this-\u003eservice-\u003equeries_reports-\u003eget($queryId, $reportId);\n\n// Regularly poll report status using exponential backoff.\nwhile (\n $report-\u003egetMetadata()-\u003egetStatus()-\u003egetState() !== \"DONE\"\n && $report-\u003egetMetadata()-\u003egetStatus()-\u003egetState() !== \"FAILED\"\n) {\n\n // If the operation has exceeded the set deadline, throw an exception.\n if (time() - $startTime \u003e $maxRetryElapsedTime) {\n printf('SDF download task processing deadline exceeded\\n');\n break;\n }\n\n // Generate the next sleep interval using exponential backoff logic.\n $sleepInterval = min(\n $maxRetryInterval,\n rand(\n max($minRetryInterval, $sleepInterval),\n max($minRetryInterval, $sleepInterval * 3)\n )\n );\n\n // Sleep before retrieving the report again.\n printf(\n 'Report is %d still running, sleeping for %d seconds\u003cbr\u003e',\n $reportId,\n $sleepInterval\n );\n sleep($sleepInterval);\n\n // Retrieve the report.\n $report = $this-\u003eservice-\u003equeries_reports-\u003eget($queryId, $reportId);\n}\n\n// Print the result of the report generation.\nif($report-\u003egetMetadata()-\u003egetStatus()-\u003egetState() == \"DONE\") {\n printf('Report %d was successfully generated.\u003cbr\u003e', $reportId);\n} else if($report-\u003egetMetadata()-\u003egetStatus()-\u003egetState() == \"FAILED\") {\n printf('Report %d finished in error.\u003cbr\u003e', $reportId);\n} else {\n print('Report generation deadline exceeded.\u003cbr\u003e');\n}\n```"]]