diff --git a/spanner/google/cloud/spanner/session.py b/spanner/google/cloud/spanner/session.py index 04fcacea38ee..33a1a8b2838b 100644 --- a/spanner/google/cloud/spanner/session.py +++ b/spanner/google/cloud/spanner/session.py @@ -24,6 +24,7 @@ # pylint: disable=ungrouped-imports from google.cloud.exceptions import NotFound +from google.cloud.exceptions import GrpcRendezvous from google.cloud.spanner._helpers import _options_with_prefix from google.cloud.spanner.batch import Batch from google.cloud.spanner.snapshot import Snapshot @@ -286,7 +287,7 @@ def run_in_transaction(self, func, *args, **kw): txn.begin() try: return_value = func(txn, *args, **kw) - except GaxError as exc: + except (GaxError, GrpcRendezvous) as exc: _delay_until_retry(exc, deadline) del self._transaction continue @@ -318,7 +319,12 @@ def _delay_until_retry(exc, deadline): :type deadline: float :param deadline: maximum timestamp to continue retrying the transaction. """ - if exc_to_code(exc.cause) != StatusCode.ABORTED: + if isinstance(exc, GrpcRendezvous): # pragma: NO COVER see #3663 + cause = exc + else: + cause = exc.cause + + if exc_to_code(cause) != StatusCode.ABORTED: raise now = time.time() @@ -326,7 +332,7 @@ def _delay_until_retry(exc, deadline): if now >= deadline: raise - delay = _get_retry_delay(exc) + delay = _get_retry_delay(cause) if delay is not None: if now + delay > deadline: @@ -336,7 +342,7 @@ def _delay_until_retry(exc, deadline): # pylint: enable=misplaced-bare-raise -def _get_retry_delay(exc): +def _get_retry_delay(cause): """Helper for :func:`_delay_until_retry`. :type exc: :class:`google.gax.errors.GaxError` @@ -345,7 +351,7 @@ def _get_retry_delay(exc): :rtype: float :returns: seconds to wait before retrying the transaction. """ - metadata = dict(exc.cause.trailing_metadata()) + metadata = dict(cause.trailing_metadata()) retry_info_pb = metadata.get('google.rpc.retryinfo-bin') if retry_info_pb is not None: retry_info = RetryInfo()