Skip to content

Commit 1f3c074

Browse files
jsondaicopybara-github
authored andcommitted
feat: GenAI Client(evals) - exponential backoff for Gemini agent interaction polling
PiperOrigin-RevId: 947932603
1 parent 66d4837 commit 1f3c074

2 files changed

Lines changed: 155 additions & 81 deletions

File tree

agentplatform/_genai/_evals_common.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,24 +1019,34 @@ def _agent_resource_to_agent_info(
10191019
["completed", "failed", "cancelled", "incomplete", "budget_exceeded"]
10201020
)
10211021

1022+
_INITIAL_POLL_INTERVAL_SECONDS = 2.0
1023+
_MAX_POLL_INTERVAL_SECONDS = 30.0
1024+
_POLL_BACKOFF_MULTIPLIER = 2.0
1025+
10221026

10231027
def _await_interaction(
10241028
interactions_client: "_InteractionsRestClient",
10251029
interaction: dict[str, Any],
1026-
poll_interval_seconds: float = 2.0,
1030+
initial_poll_interval_seconds: float = _INITIAL_POLL_INTERVAL_SECONDS,
1031+
max_poll_interval_seconds: float = _MAX_POLL_INTERVAL_SECONDS,
1032+
poll_backoff_multiplier: float = _POLL_BACKOFF_MULTIPLIER,
10271033
timeout_seconds: float = 600.0,
10281034
) -> dict[str, Any]:
10291035
"""Polls a background interaction until it reaches a terminal state.
10301036
10311037
Gemini agent interactions must run in the background (`background=True`), so
10321038
`create` returns before the model output is ready. This polls
10331039
`interactions.get` until the interaction reaches a terminal state and then
1034-
returns the resolved interaction.
1040+
returns the resolved interaction. The delay between polls grows
1041+
exponentially (capped at `max_poll_interval_seconds`) to avoid hitting rate
1042+
limits when evaluating large datasets.
10351043
10361044
Args:
10371045
interactions_client: The interactions client used to poll.
10381046
interaction: The interaction returned by `create`.
1039-
poll_interval_seconds: Delay between poll attempts.
1047+
initial_poll_interval_seconds: Delay before the first poll.
1048+
max_poll_interval_seconds: Upper bound for the poll interval.
1049+
poll_backoff_multiplier: Factor the interval grows by after each poll.
10401050
timeout_seconds: Maximum time to wait before raising.
10411051
10421052
Returns:
@@ -1049,11 +1059,18 @@ def _await_interaction(
10491059
return interaction
10501060
interaction_id = interaction.get("id")
10511061
deadline = time.monotonic() + timeout_seconds
1052-
while time.monotonic() < deadline:
1053-
time.sleep(poll_interval_seconds)
1062+
poll_interval = initial_poll_interval_seconds
1063+
while True:
1064+
remaining = deadline - time.monotonic()
1065+
if remaining <= 0:
1066+
break
1067+
time.sleep(min(poll_interval, remaining))
10541068
interaction = interactions_client.get(interaction_id)
10551069
if interaction.get("status") in _INTERACTION_TERMINAL_STATES:
10561070
return interaction
1071+
poll_interval = min(
1072+
poll_interval * poll_backoff_multiplier, max_poll_interval_seconds
1073+
)
10571074
raise TimeoutError(
10581075
f"Interaction {interaction_id} did not complete within"
10591076
f" {timeout_seconds} seconds."

0 commit comments

Comments
 (0)