Skip to content

fix: handle credentials lifecycle in BigQuery analytics plugin#5467

Draft
caohy1988 wants to merge 4 commits intogoogle:mainfrom
caohy1988:fix/bqaa-credentials-lifecycle
Draft

fix: handle credentials lifecycle in BigQuery analytics plugin#5467
caohy1988 wants to merge 4 commits intogoogle:mainfrom
caohy1988:fix/bqaa-credentials-lifecycle

Conversation

@caohy1988
Copy link
Copy Markdown

@caohy1988 caohy1988 commented Apr 24, 2026

Summary

Fixes lifecycle issues with the credentials parameter introduced in 34713fb4.

Changes

1. Pickle safety — try-preserve, fallback-drop

__getstate__ tests whether _user_credentials is picklable:

  • Picklable (service-account, AnonymousCredentials): preserved — survives pickle and restored via __setstate__ so the plugin uses the user's identity after unpickle.
  • Non-picklable (compute_engine.Credentials with requests.Session): dropped gracefully — falls back to ADC after unpickle.

_credentials (the active/resolved credentials) is always cleared since it may hold resolved ADC state. On unpickle, __setstate__ restores it from _user_credentials when available.

2. Fork safety — documented user-provided credential limitation

_reset_runtime_state() sets _credentials = _user_credentials. For ADC-resolved credentials (_user_credentials is None), this clears stale credentials for re-resolution. For user-provided credentials, the original object is kept — we cannot re-create it. The comment documents this: the user is responsible for providing fork-safe credentials.

3. GCS client — credentials passed correctly

GCSOffloader.__init__ always creates a storage.Client eagerly (storage_client or storage.Client(...) at line 1329). This was also true before the credentials commit. The fix passes explicit credentials when available and lets ADC resolve when not, matching the bigquery.Client and BigQueryWriteAsyncClient patterns.

4. Benign race on _credentials resolution documented

When multiple event loops call _create_loop_state() concurrently, both can resolve ADC redundantly. This is idempotent and benign, now documented.

Test plan

  • 208 tests pass, 0 regressions
  • test_pickle_preserves_picklable_credentials — picklable user credentials survive round-trip
  • test_pickle_drops_non_picklable_credentials — non-picklable credentials dropped, plugin falls back to ADC
  • Existing test_pickle_safety and test_custom_credentials_used pass

🤖 Generated with Claude Code

Fixes several issues introduced by the credentials parameter addition
(34713fb):

- Clear _credentials in __getstate__ so non-picklable credential types
  (e.g., compute_engine.Credentials with requests.Session) don't break
  Vertex AI Agent Engine deployment via cloudpickle.  Credentials are
  re-resolved from the user-provided value or ADC on unpickle.

- Clear _credentials in _reset_runtime_state so stale HTTP transport
  state in credential objects doesn't carry across fork boundaries.

- Restore lazy storage.Client creation — only construct it when
  explicit credentials are provided; otherwise let GCSOffloader
  create a default client on first use.  Avoids unnecessary GCP
  client initialization when GCS offloading is not triggered.

- Document the benign race on _credentials resolution when multiple
  event loops call _create_loop_state concurrently.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@google-cla
Copy link
Copy Markdown

google-cla Bot commented Apr 24, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@caohy1988 caohy1988 marked this pull request as draft April 24, 2026 05:42
@adk-bot adk-bot added the core [Component] This issue is related to the core interface and implementation label Apr 24, 2026
@adk-bot
Copy link
Copy Markdown
Collaborator

adk-bot commented Apr 24, 2026

Response from ADK Triaging Agent

Hello @caohy1988, thank you for creating this PR!

This PR is a bug fix, could you please associate the github issue with this PR? If there is no existing issue, could you please create one?

In addition, it looks like you haven't signed the Contributor License Agreement (CLA) yet. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). Please visit https://cla.developers.google.com/ to see your current agreements or to sign a new one.

This information will help reviewers to review your PR more efficiently. Thanks!

caohy1988 and others added 3 commits April 23, 2026 22:49
Addresses review feedback:

- Non-picklable user-provided credentials (e.g., compute_engine with
  requests.Session) broke pickle.dumps() because _user_credentials
  was preserved in __getstate__.  Now both _credentials and
  _user_credentials are cleared; credentials re-resolve via ADC
  after unpickle.

- Fork safety: _reset_runtime_state documents that user-provided
  credentials are kept as-is (we cannot re-create them), while
  ADC-resolved credentials are cleared for re-resolution.

- GCS client: always pass credentials explicitly when available;
  GCSOffloader.__init__ always creates a client eagerly (the "lazy
  restoration" claim in the previous commit was incorrect — the
  pre-credentials code had the same eager behavior).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous commit cleared both _credentials and _user_credentials
unconditionally in __getstate__, silently dropping picklable user
credentials (service-account, AnonymousCredentials) after unpickle.
This caused the plugin to fall back to ADC instead of the user's
configured identity.

Now __getstate__ tests whether _user_credentials is picklable:
- Picklable: preserved — survives pickle and restored on unpickle
- Non-picklable: dropped gracefully — falls back to ADC

Adds two tests covering both paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
A valid picklable credential subclass that defines __bool__ as False
would not be restored into _credentials, causing silent ADC fallback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@haiyuan-eng-google haiyuan-eng-google self-requested a review April 24, 2026 07:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core [Component] This issue is related to the core interface and implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants