Skip to content

Commit 9fd7d09

Browse files
authored
Fix test retry on throttling (#34786)
* Change google-api-core version * Update ThrottlingHandler logic * Fix formatting * Add dynamic arg name choice to ThrottlingHandler * Fix formatting * Fix formatting
1 parent 82ef9d8 commit 9fd7d09

File tree

2 files changed

+30
-4
lines changed

2 files changed

+30
-4
lines changed

sdks/python/apache_beam/io/gcp/gcsio_retry.py

+30-3
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,40 @@
2222
import inspect
2323
import logging
2424
import math
25+
from itertools import tee
2526

27+
from google.api_core import __version__ as _api_core_version
2628
from google.api_core import exceptions as api_exceptions
2729
from google.api_core import retry
2830
from google.cloud.storage.retry import DEFAULT_RETRY
2931
from google.cloud.storage.retry import _should_retry # pylint: disable=protected-access
32+
from packaging import version
3033

3134
from apache_beam.metrics.metric import Metrics
3235
from apache_beam.options.pipeline_options import GoogleCloudOptions
3336

3437
_LOGGER = logging.getLogger(__name__)
3538

3639
__all__ = ['DEFAULT_RETRY_WITH_THROTTLING_COUNTER']
40+
_MIN_SLEEP_ARG_SWITCH_VERSION = version.parse("2.25.0rc0")
41+
_LEGACY_SLEEP_ARG_NAME = "next_sleep"
42+
_CURRENT_SLEEP_ARG_NAME = "sleep_iterator"
3743

3844

3945
class ThrottlingHandler(object):
4046
_THROTTLED_SECS = Metrics.counter('gcsio', "cumulativeThrottlingSeconds")
4147

48+
def __init__(self):
49+
# decide which arg name google-api-core uses
50+
try:
51+
core_ver = version.parse(_api_core_version)
52+
except Exception:
53+
core_ver = version.parse("0")
54+
if core_ver < _MIN_SLEEP_ARG_SWITCH_VERSION:
55+
self._sleep_arg = _LEGACY_SLEEP_ARG_NAME
56+
else:
57+
self._sleep_arg = _CURRENT_SLEEP_ARG_NAME
58+
4259
def __call__(self, exc):
4360
if isinstance(exc, api_exceptions.TooManyRequests):
4461
_LOGGER.debug('Caught GCS quota error (%s), retrying.', exc.reason)
@@ -54,9 +71,19 @@ def __call__(self, exc):
5471
_LOGGER.warning('cannot inspect the caller stack frame')
5572
return
5673

57-
# next_sleep is one of the arguments in the caller
58-
# i.e. _retry_error_helper() in google/api_core/retry/retry_base.py
59-
sleep_seconds = prev_frame.f_locals.get("next_sleep", 0)
74+
# Determine which retry helper argument to inspect in
75+
# google/api_core/retry/retry_base.py’s _retry_error_helper():
76+
# - versions < 2.25.0rc0 use “next_sleep”
77+
# - versions ≥ 2.25.0rc0 use “sleep_iterator”
78+
if self._sleep_arg == _LEGACY_SLEEP_ARG_NAME:
79+
sleep_seconds = prev_frame.f_locals.get(self._sleep_arg, 0)
80+
else:
81+
sleep_iterator = prev_frame.f_locals.get(self._sleep_arg, iter([]))
82+
sleep_iterator, sleep_iterator_copy = tee(sleep_iterator)
83+
try:
84+
sleep_seconds = next(sleep_iterator_copy)
85+
except StopIteration:
86+
sleep_seconds = 0
6087
ThrottlingHandler._THROTTLED_SECS.inc(math.ceil(sleep_seconds))
6188

6289

sdks/python/apache_beam/io/gcp/gcsio_retry_test.py

-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
api_exceptions = None
3535

3636

37-
@unittest.skip("https://github.com/apache/beam/issues/34736")
3837
@unittest.skipIf((gcsio_retry is None or api_exceptions is None),
3938
'GCP dependencies are not installed')
4039
class TestGCSIORetry(unittest.TestCase):

0 commit comments

Comments
 (0)