aboutsummaryrefslogtreecommitdiff
path: root/google
diff options
context:
space:
mode:
authorChristopher Wilcox <crwilcox@google.com>2020-01-30 15:29:28 -0800
committerGitHub <noreply@github.com>2020-01-30 15:29:28 -0800
commit2b103b60ece16a1e1bc98cfda7ec375191a90f75 (patch)
tree6549bfb29e52911a6a47f7fec2c242bf3b835d3c /google
parent14f1f34e013c90fed2da2918625083d299fda557 (diff)
downloadpython-api-core-2b103b60ece16a1e1bc98cfda7ec375191a90f75.tar.gz
fix: consume part of StreamingResponseIterator to support failure while under a retry context (#10206)
Diffstat (limited to 'google')
-rw-r--r--google/api_core/grpc_helpers.py18
1 files changed, 18 insertions, 0 deletions
diff --git a/google/api_core/grpc_helpers.py b/google/api_core/grpc_helpers.py
index 4d63beb..c47b09f 100644
--- a/google/api_core/grpc_helpers.py
+++ b/google/api_core/grpc_helpers.py
@@ -65,6 +65,19 @@ class _StreamingResponseIterator(grpc.Call):
def __init__(self, wrapped):
self._wrapped = wrapped
+ # This iterator is used in a retry context, and returned outside after init.
+ # gRPC will not throw an exception until the stream is consumed, so we need
+ # to retrieve the first result, in order to fail, in order to trigger a retry.
+ try:
+ self._stored_first_result = six.next(self._wrapped)
+ except TypeError:
+ # It is possible the wrapped method isn't an iterable (a grpc.Call
+ # for instance). If this happens don't store the first result.
+ pass
+ except StopIteration:
+ # ignore stop iteration at this time. This should be handled outside of retry.
+ pass
+
def __iter__(self):
"""This iterator is also an iterable that returns itself."""
return self
@@ -76,8 +89,13 @@ class _StreamingResponseIterator(grpc.Call):
protobuf.Message: A single response from the stream.
"""
try:
+ if hasattr(self, "_stored_first_result"):
+ result = self._stored_first_result
+ del self._stored_first_result
+ return result
return six.next(self._wrapped)
except grpc.RpcError as exc:
+ # If the stream has already returned data, we cannot recover here.
six.raise_from(exceptions.from_grpc_error(exc), exc)
# Alias needed for Python 2/3 support.