Skip to content

[Java] Honor withMaxRetryJobs for bounded BigQueryIO file loads - #39938

Open
mxtymoshyk wants to merge 4 commits into
apache:masterfrom
mxtymoshyk:bq-max-retry-jobs-bounded
Open

mxtymoshyk wants to merge 4 commits into
apache:masterfrom
mxtymoshyk:bq-max-retry-jobs-bounded

Conversation

@mxtymoshyk

Copy link
Copy Markdown
Contributor

BigQueryIO.Write.withMaxRetryJobs was silently ignored by every bounded (batch) pipeline. continueExpandTyped only forwarded the value to BatchLoads when the input was IsBounded.UNBOUNDED, so a batch write always used BatchLoads.DEFAULT_MAX_RETRY_JOBS (3) no matter what the user asked for. The failure surfaces only as reached max retries: 3 in the exception text after the job has already given up.

The setting is now honored in both modes. Pipelines that never call withMaxRetryJobs keep exactly the limits they have today: 3 for bounded, 1000 for unbounded.

The Javadoc said only "If set, this will set the max number of retry of batch load jobs." It now states that the setting applies to FILE_LOADS only and what the two defaults are, which was the second half of the issue.

fixes #28281

How the default is preserved

Write.getMaxRetryJobs() becomes @Nullable Integer and is no longer given a value in BigQueryIO.write(). Null means "user never asked", which is what makes it possible to honor an explicit value in batch without also raising the batch default from 3 to 1000. This mirrors getMaxFilesPerBundle / getMaxFileSize in the same Write class -- nullable, absent from the write() defaults, and applied under a null check at expansion time.

The two default values now live next to each other as BatchLoads.DEFAULT_MAX_RETRY_JOBS and BatchLoads.DEFAULT_MAX_RETRY_JOBS_UNBOUNDED, so the reason streaming retries far more than batch is visible in one place.

Notes for reviewers

  • Behaviour for existing users is unchanged unless they call withMaxRetryJobs, and if they do call it on a batch pipeline they currently get nothing.
  • maxRetryJobs only ever reaches the FILE_LOADS branch of continueExpandTyped, so the "only applies to Method#FILE_LOADS" sentence in the Javadoc is accurate rather than a guess.
  • BigQueryIOTranslation needed no change: max_retry_jobs was already declared with addNullableInt32Field, toConfigRow can put a null, and fromConfigRow already skips a null. BigQueryIOTranslationTest passes unchanged.
  • Public API is unchanged -- withMaxRetryJobs(int) keeps its signature. Only the package-private AutoValue accessor and setter changed type.
  • testWriteFailedJobs now asserts reached max retries: 3 rather than the bare substring. That pins the bounded default so a future change cannot quietly move it.
  • The new test testWriteFailedJobsRespectsMaxRetryJobsWhenBounded reuses the existing testWriteFailedJobs harness (CREATE_NEVER against a table that does not exist, so every load job attempt fails) and sets withMaxRetryJobs(1). PendingJob puts the applied limit into its own failure message, so the assertion reads the value that actually reached BatchLoads. A low value also keeps the test fast, since each retry costs a backoff sleep.
  • Verified locally on :sdks:java:io:google-cloud-platform. BigQueryIOWriteTest.testWriteFailedJobs*, testMaxRetryJobs* and the whole of BigQueryIOTranslationTest pass (21 run, 0 failures). Restoring only the old if (IsBounded.UNBOUNDED...) guard makes testWriteFailedJobsRespectsMaxRetryJobsWhenBounded[0] fail while testWriteFailedJobs still passes, so the new test covers the fix and nothing else.
  • I did not change the unbounded default of 1000, which is the subject of the separate [Bug]: BigQuery connector sets insane high maxRetryJobs for unbounded collections #28282. Asserting it end to end would mean sitting through 1000 backoff-spaced retries, so it is covered only by the null-default path being unchanged.
  • No prior PR referenced this issue.

@github-actions

Copy link
Copy Markdown
Contributor

Assigning reviewers:

R: @chamikaramj for label java.

Note: If you would like to opt out of this review, comment assign to next reviewer.

Available commands:

  • stop reviewer notifications - opt out of the automated review tooling
  • remind me after tests pass - tag the comment author after tests pass
  • waiting on author - shift the attention set back to the author (any comment or push by the author will return the attention set to the reviewers)

The PR bot will only process comments in the main thread (not review comments).

@mxtymoshyk
mxtymoshyk force-pushed the bq-max-retry-jobs-bounded branch from 6d6879a to 1dbfb0b Compare September 3, 2026 04:26
@github-actions

Copy link
Copy Markdown
Contributor

Reminder, please take a look at this pr: @chamikaramj

@github-actions

Copy link
Copy Markdown
Contributor

Assigning new set of reviewers because Pr has gone too long without review. If you would like to opt out of this review, comment assign to next reviewer:

R: @Abacn for label java.

Available commands:

  • stop reviewer notifications - opt out of the automated review tooling
  • remind me after tests pass - tag the comment author after tests pass
  • waiting on author - shift the attention set back to the author (any comment or push by the author will return the attention set to the reviewers)

@github-actions

Copy link
Copy Markdown
Contributor

Reminder, please take a look at this pr: @Abacn

@github-actions

Copy link
Copy Markdown
Contributor

Assigning new set of reviewers because Pr has gone too long without review. If you would like to opt out of this review, comment assign to next reviewer:

R: @chamikaramj for label java.

Available commands:

  • stop reviewer notifications - opt out of the automated review tooling
  • remind me after tests pass - tag the comment author after tests pass
  • waiting on author - shift the attention set back to the author (any comment or push by the author will return the attention set to the reviewers)

@mxtymoshyk
mxtymoshyk force-pushed the bq-max-retry-jobs-bounded branch from 1dbfb0b to aacd74f Compare September 25, 2026 10:49
@mxtymoshyk

Copy link
Copy Markdown
Contributor Author

Rebased. Since release-2.77 was cut, I moved the upgrade threshold to 2.78.0 (aacd74f).

@mxtymoshyk

Copy link
Copy Markdown
Contributor Author

The only failing check is a Pub/Sub test (PubsubSchemaIT) that couldn't authenticate with GCP. It looks like a CI credentials hiccup rather than something related to this change, and all the BigQuery tests pass.

Could someone re-run it when you have a moment?

@mxtymoshyk
mxtymoshyk force-pushed the bq-max-retry-jobs-bounded branch from 959675b to a731331 Compare September 26, 2026 20:47
@mxtymoshyk

Copy link
Copy Markdown
Contributor Author

Rebased onto current master to resolve a CHANGES.md conflict, and all checks pass now, including the Pub/Sub test that failed earlier.

@mxtymoshyk
mxtymoshyk force-pushed the bq-max-retry-jobs-bounded branch 3 times, most recently from 9411263 to 9c03612 Compare October 7, 2026 07:46
@mxtymoshyk
mxtymoshyk force-pushed the bq-max-retry-jobs-bounded branch 4 times, most recently from 51f0ec6 to 3df0fbf Compare October 13, 2026 17:06
@chamikaramj
chamikaramj force-pushed the bq-max-retry-jobs-bounded branch from 3df0fbf to a0a6cd2 Compare October 19, 2026 20:05
@chamikaramj

Copy link
Copy Markdown
Contributor

@bvolpato will you be able to continue the review here ?

@chamikaramj

Copy link
Copy Markdown
Contributor

LGTM, but tests have to pass before merging.

BigQueryIO.Write only forwarded maxRetryJobs to BatchLoads when the input
was unbounded, so every batch pipeline used BatchLoads' own default of 3
retries and withMaxRetryJobs did nothing at all. A user who asked for
fewer retries on a permanently failing load job, or for more, got neither
and only saw "reached max retries: 3" after the write had given up.

The value now reaches BatchLoads in both modes. Write.getMaxRetryJobs
becomes a nullable Integer that BigQueryIO.write() leaves unset, so an
absent setting can still fall back to the two different defaults the two
modes have always had: 3 for bounded, 1000 for unbounded.

Also documents on withMaxRetryJobs that the setting applies to FILE_LOADS
only and what happens when it is not called.
BigQueryIO.write() used to seed maxRetryJobs with 1000 whether or not the
pipeline ever called withMaxRetryJobs, so every config row written by an
older SDK carries that value. fromConfigRow restored it, and the new
expand() would have read it as an explicit setting, raising bounded
FILE_LOADS retries from 3 to 1000 on upgrade.

A pre-2.77.0 row holding exactly 1000 says nothing about what the user
asked for, so drop it and let each mode fall back to the default it used
before: 3 for bounded and 1000 for unbounded. Any other value was chosen
deliberately and is carried over.
release-2.77 was cut before this change landed, so 2.77.0 still seeds
maxRetryJobs with 1000 in every config row. Treat rows from 2.77.0 and
earlier as legacy.
master now runs the nullness checker on BigQueryIOTranslation, and
getMaxRetryJobs() is nullable after this change.
@mxtymoshyk
mxtymoshyk force-pushed the bq-max-retry-jobs-bounded branch from a0a6cd2 to 2d0413f Compare October 26, 2026 06:50
@github-actions github-actions Bot added the size/m M: 50-249 lines changed label Oct 26, 2026
@mxtymoshyk

Copy link
Copy Markdown
Contributor Author

Rebased onto current master (2d0413f). All checks pass, and the change is in the 2.78.0 section of CHANGES.md.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: BigQuery connector ignores maxRetryJobs for bounded collections

3 participants