Skip to content

fix(plugins): add opt-in exactly-once delivery to BigQueryAgentAnalyticsPlugin#6466

Draft
addenergyx wants to merge 2 commits into
google:mainfrom
addenergyx:fix/bigquery-analytics-exactly-once-delivery
Draft

fix(plugins): add opt-in exactly-once delivery to BigQueryAgentAnalyticsPlugin#6466
addenergyx wants to merge 2 commits into
google:mainfrom
addenergyx:fix/bigquery-analytics-exactly-once-delivery

Conversation

@addenergyx

@addenergyx addenergyx commented Jul 24, 2026

Copy link
Copy Markdown

Closes: #6465

BatchProcessor._write_rows_with_retry writes to BigQuery's shared _default Storage Write API stream, which is at-least-once and rejects an append offset. It resubmits the same batch after a client-side timeout or UNAVAILABLE/INTERNAL, so if the first append actually landed but the ack was lost, the retry can write a byte-identical duplicate row. Evidence and repro in #6465.

Adds an opt-in exactly_once_delivery flag to BigQueryLoggerConfig (default False, no behavior change for existing users). When enabled, each event loop's BatchProcessor writes to its own COMMITTED stream with a tracked append offset instead of _default. A retry after an ambiguous failure resends the same offset; BigQuery returns ALREADY_EXISTS instead of writing it again, which is treated as a confirmed no-op rather than an error. An unexpected OUT_OF_RANGE (offset desync) drops the batch loudly rather than guessing a corrective offset. Similar in spirit to Apache Beam's use_at_least_once=False on WriteToBigQuery.

Added TestExactlyOnceDelivery (5 tests) covering the offset lifecycle, including the exact timeout-then-ALREADY_EXISTS sequence from production. Full suite (tox, py310-py314): 9231 passed, 0 failed on every version. Not yet tested against a live BigQuery project.

…icsPlugin

BatchProcessor retries an ambiguous write (timeout, UNAVAILABLE, INTERNAL)
by resubmitting the same batch to BigQuery's `_default` stream, which is
at-least-once and rejects an append offset -- so a retry after a lost ack
can write a byte-identical duplicate row. Add an opt-in
`exactly_once_delivery` config flag that instead writes to a dedicated
COMMITTED stream per event loop with a tracked append offset, so a retry
resends the same offset and BigQuery rejects the duplicate (ALREADY_EXISTS)
instead of applying it twice. Default is unchanged.

Fixes google#6465
…ests

- Drop the redundant offset_for_batch local in
  BatchProcessor._write_rows_with_retry; self._next_offset is only ever
  mutated on a confirmed outcome within a single (serial) call, so reading
  it directly is equivalent and removes four "is not None" checks.
- Move the OUT_OF_RANGE branch above the generic error-code log so it no
  longer double-logs (it previously logged both the generic warning and its
  own error message for the same event).
- Extract the repeated table-resource-path f-string into
  _table_resource_path().
- Hoist _stub_arrow_prep/_make_batch_processor to module level in the test
  file; TestDropStats and TestExactlyOnceDelivery previously carried
  byte-identical/near-identical copies.

No behavior change; full suite still green.
@adk-bot adk-bot added the tracing [Component] This issue is related to OpenTelemetry tracing label Jul 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tracing [Component] This issue is related to OpenTelemetry tracing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BigQueryAgentAnalyticsPlugin can duplicate rows when writes are retried

3 participants