Skip to content

Commit a38d8cc

Browse files
committed
wip(not tested): initial approach for testing retries
1 parent d18d9b5 commit a38d8cc

File tree

1 file changed

+47
-0
lines changed

1 file changed

+47
-0
lines changed

google/api_core/retry/retry_unary.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def check_if_exists():
5757
from __future__ import annotations
5858

5959
import functools
60+
import logging
6061
import sys
6162
import time
6263
import inspect
@@ -81,6 +82,7 @@ def check_if_exists():
8182

8283
_ASYNC_RETRY_WARNING = "Using the synchronous google.api_core.retry.Retry with asynchronous calls may lead to unexpected results. Please use google.api_core.retry_async.AsyncRetry instead."
8384

85+
_LOGGER = logging.getLogger(__name__)
8486

8587
def retry_target(
8688
target: Callable[_P, _R],
@@ -138,17 +140,62 @@ def retry_target(
138140

139141
deadline = time.monotonic() + timeout if timeout is not None else None
140142
error_list: list[Exception] = []
143+
attempt = 0
144+
rpc_call_id = None
141145

142146
for sleep in sleep_generator:
143147
try:
148+
if logging.isEnabledFor(logging.DEBUG):
149+
# Is there an easy way of getting the fields of interest at this level in the call?
150+
#
151+
# Otherwise, maybe we compute the request ID in the client and pass it in to the retry logic as a parameter
152+
# client:
153+
# response = Library.listBooks(..., requestID=582) # the 582 would be a unique ID computed on the fly
154+
# api_core:
155+
# loggingDebug(f"Calling {rpc_call_id}:{attempt} for request {requestID}")
156+
# Logging output:
157+
# TIME1: client: Initiating RPC ListBooks (requestID=582, details=....)
158+
# TIME2: google_api_core: Call 582:0 STARTED
159+
# TIME3: google_api_core: Call 582:0 FAILED
160+
# TIME4: google_api_core: Call 582:1 STARTED
161+
# TIME5: google_api_core: Call 582:1 SUCCEEDED
162+
#
163+
# Note that this means we have two uses of IDs: one
164+
# for the high-level call at the client level
165+
# (request_id), and one for each individual RPC retry
166+
# call (call_id); the latter is the concatenation of
167+
# the request_id and the retry-attempt. I think that
168+
# makes sense for logging purposes.
169+
#
170+
# Anyway, the following code does NOT assume the above.
171+
172+
rpc_call_id = rpc_call_id or hash(target)
173+
logging.debug(f"Call {rpc_call_id}:{attempt} STARTED.",
174+
extra={
175+
"rpcCallId": rpc_call_id,
176+
"retryAttempt": attempt,
177+
"rpcCallStatus": "START"})
178+
attempt += 1
144179
result = target()
145180
if inspect.isawaitable(result):
146181
warnings.warn(_ASYNC_RETRY_WARNING)
182+
if logging.isEnabledFor(logging.DEBUG):
183+
logging.debug(f"Call {rpc_call_id}:{attempt}. SUCCEEDED.",
184+
extra={
185+
"rpcCallId": rpc_call_id,
186+
"retryAttempt": attempt,
187+
"rpcCallStatus": "SUCCESS"})
147188
return result
148189

149190
# pylint: disable=broad-except
150191
# This function explicitly must deal with broad exceptions.
151192
except Exception as exc:
193+
if logging.isEnabledFor(logging.DEBUG):
194+
logging.debug(f"Call {rpc_call_id}:{attempt}. FAILED.",
195+
extra={
196+
"rpcCallId": rpc_call_id,
197+
"retryAttempt": attempt,
198+
"rpcCallStatus": "FAILURE"})
152199
# defer to shared logic for handling errors
153200
_retry_error_helper(
154201
exc,

0 commit comments

Comments
 (0)