Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 325
fix: avoid unnecessary API call in QueryJob.result() when job is already finished#1900
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
0c9a8a207839b551123156297efde5990ebfddb5576a43cfd12fa9fb5149c254ee497508373bc2a587aaf7f1e81e42d8adFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -17,11 +17,11 @@ | ||||||||
| import concurrent.futures | ||||||||
| import copy | ||||||||
| import re | ||||||||
| import time | ||||||||
| import typing | ||||||||
| from typing import Any, Dict, Iterable, List, Optional, Union | ||||||||
| from google.api_core import exceptions | ||||||||
| from google.api_core.future import polling as polling_future | ||||||||
| from google.api_core import retry as retries | ||||||||
| import requests | ||||||||
| @@ -1383,7 +1383,7 @@ def _begin(self, client=None, retry=DEFAULT_RETRY, timeout=None): | ||||||||
| def _reload_query_results( | ||||||||
| self, retry: "retries.Retry" = DEFAULT_RETRY, timeout: Optional[float] = None | ||||||||
| ): | ||||||||
| """Refresh the cached query results. | ||||||||
| """Refresh the cached query results unless already cached and complete. | ||||||||
| Args: | ||||||||
| retry (Optional[google.api_core.retry.Retry]): | ||||||||
| @@ -1392,6 +1392,8 @@ def _reload_query_results( | ||||||||
| The number of seconds to wait for the underlying HTTP transport | ||||||||
| before using ``retry``. | ||||||||
| """ | ||||||||
| # Optimization: avoid a call to jobs.getQueryResults if it's already | ||||||||
| # been fetched, e.g. from jobs.query first page of results. | ||||||||
| if self._query_results and self._query_results.complete: | ||||||||
| return | ||||||||
| @@ -1430,40 +1432,6 @@ def _reload_query_results( | ||||||||
| timeout=transport_timeout, | ||||||||
| ) | ||||||||
| def _done_or_raise(self, retry=DEFAULT_RETRY, timeout=None): | ||||||||
| """Check if the query has finished running and raise if it's not. | ||||||||
| If the query has finished, also reload the job itself. | ||||||||
| """ | ||||||||
| # If an explicit timeout is not given, fall back to the transport timeout | ||||||||
| # stored in _blocking_poll() in the process of polling for job completion. | ||||||||
| transport_timeout = timeout if timeout is not None else self._transport_timeout | ||||||||
| try: | ||||||||
| self._reload_query_results(retry=retry, timeout=transport_timeout) | ||||||||
| except exceptions.GoogleAPIError as exc: | ||||||||
| # Reloading also updates error details on self, thus no need for an | ||||||||
| # explicit self.set_exception() call if reloading succeeds. | ||||||||
| try: | ||||||||
| self.reload(retry=retry, timeout=transport_timeout) | ||||||||
| except exceptions.GoogleAPIError: | ||||||||
| # Use the query results reload exception, as it generally contains | ||||||||
| # much more useful error information. | ||||||||
| self.set_exception(exc) | ||||||||
| finally: | ||||||||
| return | ||||||||
| # Only reload the job once we know the query is complete. | ||||||||
| # This will ensure that fields such as the destination table are | ||||||||
| # correctly populated. | ||||||||
| if not self._query_results.complete: | ||||||||
| raise polling_future._OperationNotComplete() | ||||||||
| else: | ||||||||
| try: | ||||||||
| self.reload(retry=retry, timeout=transport_timeout) | ||||||||
| except exceptions.GoogleAPIError as exc: | ||||||||
| self.set_exception(exc) | ||||||||
| ||||||||
| self.set_exception(exception) |
Which we call from _set_properties
| self._set_future_result() |
Which we call from reload
| self._set_properties(api_response) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uh oh, if jobs.getQueryResults fails because the job failed it can throw an exception but restart_query_job will still be False.
But we don't want restart_query_job = True because sometimes this can raise an ambiguous exception such as quota exceeded, where we don't know if it's the job quota and it's a failed job or at a higher level (Google Frontend - GFE) where the job might actually still be running and/or succeeded.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't the worst way to fail, but it'd be nice to do the jobs.get call above in case of an exception to get a chance at retrying this job if the job failed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filed #1903 to track improvements to ambiguous errors. 12fa9fb fixes an issue where we weren't actually retrying after an ambiguous failure even though we thought we were.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was overridden because we wanted
result()from the superclass to calljobs.getQueryResults, not justjobs.get(i.e.job.reload()in Python). Now that we aren't using the superclass forresult(), this method is no longer necessary.