Skip to content

Commit 74f2c9f

Browse files
author
Google Earth Engine Authors
committed
Add a method to set the max number of retries.
PiperOrigin-RevId: 651875150
1 parent 28af3ea commit 74f2c9f

2 files changed

Lines changed: 47 additions & 9 deletions

File tree

python/ee/data.py

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@
7474
# it timed out. 0 means no limit.
7575
_deadline_ms: int = 0
7676

77+
# Maximum number of times to retry a rate-limited request.
78+
_max_retries: int = 5
79+
7780
# User agent to indicate which application is calling Earth Engine
7881
_user_agent: Optional[str] = None
7982

@@ -117,9 +120,6 @@ def __init__(self):
117120
# Optional HTTP header returned to display initialization-time messages.
118121
_INIT_MESSAGE_HEADER = 'x-earth-engine-init-message' # lowercase for httplib2
119122

120-
# Maximum number of times to retry a rate-limited request.
121-
MAX_RETRIES = 5
122-
123123
# Maximum time to wait before retrying a rate-limited request (in milliseconds).
124124
MAX_RETRY_WAIT = 120000
125125

@@ -383,7 +383,7 @@ def _handle_profiling_response(response: httplib2.Response) -> None:
383383

384384

385385
def _execute_cloud_call(
386-
call: googleapiclient.http.HttpRequest, num_retries: int = MAX_RETRIES
386+
call: googleapiclient.http.HttpRequest, num_retries: Optional[int] = None
387387
) -> Any:
388388
"""Executes a Cloud API call and translates errors to EEExceptions.
389389
@@ -398,6 +398,7 @@ def _execute_cloud_call(
398398
Raises:
399399
EEException if the call fails.
400400
"""
401+
num_retries = _max_retries if num_retries is None else num_retries
401402
try:
402403
return call.execute(num_retries=num_retries)
403404
except googleapiclient.errors.HttpError as e:
@@ -472,6 +473,20 @@ def setDeadline(milliseconds: float) -> None:
472473
_install_cloud_api_resource()
473474

474475

476+
def setMaxRetries(max_retries: int) -> None:
477+
"""Sets the maximum number of retries for API requests.
478+
479+
Args:
480+
max_retries: The maximum number of retries for a request.
481+
"""
482+
if max_retries < 0:
483+
raise ValueError('max_retries must be non-negative')
484+
if max_retries >= 100:
485+
raise ValueError('Too many retries')
486+
global _max_retries
487+
_max_retries = max_retries
488+
489+
475490
@contextlib.contextmanager
476491
def profiling(hook: Any) -> Iterator[None]:
477492
# pylint: disable=g-doc-return-or-yield
@@ -511,7 +526,7 @@ def getInfo(asset_id: str) -> Optional[Any]:
511526
_get_cloud_projects()
512527
.assets()
513528
.get(name=name, prettyPrint=False)
514-
.execute(num_retries=MAX_RETRIES)
529+
.execute(num_retries=_max_retries)
515530
)
516531
except googleapiclient.errors.HttpError as e:
517532
if e.resp.status == 404:
@@ -1682,7 +1697,7 @@ def getTaskStatus(taskId: Union[List[str], str]) -> List[Any]:
16821697
_get_cloud_projects()
16831698
.operations()
16841699
.get(name=_cloud_api_utils.convert_task_id_to_operation_name(one_id))
1685-
.execute(num_retries=MAX_RETRIES)
1700+
.execute(num_retries=_max_retries)
16861701
)
16871702
result.append(_cloud_api_utils.convert_operation_to_task(operation))
16881703
except googleapiclient.errors.HttpError as e:
@@ -1885,7 +1900,7 @@ def _prepare_and_run_export(
18851900
if isinstance(params['expression'], encodable.Encodable):
18861901
params['expression'] = serializer.encode(
18871902
params['expression'], for_cloud_api=True)
1888-
num_retries = MAX_RETRIES if request_id else 0
1903+
num_retries = _max_retries if request_id else 0
18891904
return _execute_cloud_call(
18901905
export_endpoint(project=_get_projects_path(), body=params),
18911906
num_retries=num_retries)
@@ -1935,7 +1950,7 @@ def startIngestion(
19351950

19361951
# It's only safe to retry the request if there's a unique ID to make it
19371952
# idempotent.
1938-
num_retries = MAX_RETRIES if request_id else 0
1953+
num_retries = _max_retries if request_id else 0
19391954
operation = _execute_cloud_call(
19401955
_get_cloud_projects()
19411956
.image()
@@ -1987,7 +2002,7 @@ def startTableIngestion(
19872002
}
19882003
# It's only safe to retry the request if there's a unique ID to make it
19892004
# idempotent.
1990-
num_retries = MAX_RETRIES if request_id else 0
2005+
num_retries = _max_retries if request_id else 0
19912006
operation = _execute_cloud_call(
19922007
_get_cloud_projects()
19932008
.table()

python/ee/tests/data_test.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,29 @@ def testIsInitialized(self):
3434
with apitestcase.UsingCloudApi():
3535
self.assertTrue(ee.data.is_initialized())
3636

37+
def testSetMaxRetries_badValues(self):
38+
with self.assertRaises(ValueError):
39+
ee.data.setMaxRetries(-1)
40+
with self.assertRaises(ValueError):
41+
ee.data.setMaxRetries(100)
42+
43+
def testSetMaxRetries(self):
44+
mock_result = {'result': 5}
45+
ee.data.setMaxRetries(3)
46+
cloud_api_resource = mock.MagicMock()
47+
with apitestcase.UsingCloudApi(cloud_api_resource=cloud_api_resource):
48+
cloud_api_resource.projects().value().compute().execute.return_value = (
49+
mock_result
50+
)
51+
self.assertEqual(5, ee.data.computeValue(ee.Number(1)))
52+
self.assertEqual(
53+
3,
54+
cloud_api_resource.projects()
55+
.value()
56+
.compute()
57+
.execute.call_args.kwargs['num_retries'],
58+
)
59+
3760
def testListOperations(self):
3861
mock_http = mock.MagicMock(httplib2.Http)
3962
# Return in three groups.

0 commit comments

Comments
 (0)