Skip to content

Fix/streamed result set race#1512

Open
aseering wants to merge 25 commits intogoogleapis:mainfrom
aseering:fix/streamed-result-set-race
Open

Fix/streamed result set race#1512
aseering wants to merge 25 commits intogoogleapis:mainfrom
aseering:fix/streamed-result-set-race

Conversation

@aseering
Copy link
Contributor

@aseering aseering commented Mar 4, 2026

Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly:

  • Make sure to open an issue as a bug/issue before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea
  • Ensure the tests and linter pass
  • Code coverage does not decrease (if any source code was changed)
  • Appropriate docs were updated (if necessary)

Fixes #<issue_number_goes_here> 🦕

Prevents swallowing exceptions and fixes SyntaxWarning in Python 3.14.
- Replaces deprecated datetime.utcnow() with timezone-aware datetime.now(timezone.utc).
- Renames MockCredentials and MockClass to avoid pytest/unittest collection warnings.
Silently drops metrics missing instance_id to prevent 400 InvalidArgument errors from Cloud Monitoring for project-level operations.
- Fix missing imports in metrics_exporter.py

- Fix shadow datetime import in test_pool.py

- Fix exception handling in cursor.py that broke dbapi tests
… to 3.14

- Fixes 'Python interpreter 3.10 not found' error in GitHub Actions lint job.

- Fixes 'system' nox session failing because GitHub Actions only provisions Python 3.14 for it.
…directly to avoid empty transaction ValueError
…reamedResultSet variants since Pytest >=8 unhandled thread exceptions explicitly bubble up from lazy evaluation races
@aseering aseering requested review from a team as code owners March 4, 2026 20:32
@aseering aseering requested a review from ohmayr March 4, 2026 20:32
@product-auto-label product-auto-label bot added the size: l Pull request size is large. label Mar 4, 2026
@product-auto-label product-auto-label bot added api: spanner Issues related to the googleapis/python-spanner API. samples Issues that are directly related to samples. labels Mar 4, 2026
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request primarily focuses on resolving a race condition within streamed result sets, ensuring transaction IDs are correctly handled during concurrent operations. It also includes a significant update to deprecate Python 3.9 support across the project's testing and configuration. Additionally, the changes modernize datetime usage to be timezone-aware, enhance the robustness of metrics exports, and improve the reliability of backup operations and associated test cleanup routines.

Highlights

  • Streamed Result Set Race Condition Fix: Addressed a potential race condition in streamed result sets by ensuring the transaction ID is populated while holding a lock, specifically when a transaction begins inline with the first data fetch. This prevents issues where the lock might be released prematurely before the transaction ID is available.
  • Python 3.9 Deprecation: Removed Python 3.9 from various CI configurations, unit test versions, and project classifiers, indicating the deprecation of official support and testing for this Python version.
  • Timezone-Aware Datetime Modernization: Updated numerous instances of datetime.utcnow() to datetime.now(datetime.timezone.utc) across the codebase, samples, and tests to ensure consistent and timezone-aware handling of timestamps.
  • Metrics Export Robustness: Improved the Cloud Monitoring metrics exporter to ensure project_id is always present in monitored resource labels and to silently drop metrics lacking an instance_id to prevent InvalidArgument errors from the monitoring API.
  • Backup Operation Enhancements: Increased timeouts for backup creation and copy operations from 2100 seconds to 3600 seconds and added explicit timeout mechanisms to while not operation.done() loops in backup cancellation and deletion to prevent indefinite waits.
  • DB API Autocommit Behavior Refinement: Adjusted system tests for the DB API to correctly handle commit() calls in autocommit mode by wrapping them in pytest.warns to acknowledge their non-operational nature, improving test accuracy.
Changelog
  • .kokoro/presubmit/integration-regular-sessions-enabled.cfg
    • Removed Python 3.9 from the NOX_SESSION environment variable.
  • .kokoro/samples/python3.9/common.cfg
    • Removed the Python 3.9 specific common configuration file.
  • .kokoro/samples/python3.9/continuous.cfg
    • Removed the Python 3.9 specific continuous integration configuration file.
  • .kokoro/samples/python3.9/periodic-head.cfg
    • Removed the Python 3.9 specific periodic-head configuration file.
  • .kokoro/samples/python3.9/periodic.cfg
    • Removed the Python 3.9 specific periodic configuration file.
  • .kokoro/samples/python3.9/presubmit.cfg
    • Removed the Python 3.9 specific presubmit configuration file.
  • .kokoro/test-samples-impl.sh
    • Updated Python commands from python3.9 to python3 for broader compatibility.
  • .librarian/generator-input/librarian.py
    • Removed Python versions 3.7, 3.8, and 3.9 from the list of unit test Python versions.
  • .librarian/generator-input/noxfile.py
    • Changed the default Python version from 3.14 to 3.10.
    • Removed Python 3.9 from the list of unit test Python versions.
  • .librarian/generator-input/setup.py
    • Removed Python 3.9 from the programming language classifiers.
  • .librarian/state.yaml
    • Updated the constraints file reference from constraints-3.1 to constraints-3.10.
    • Removed the constraints-3.9 reference.
  • google/cloud/spanner_dbapi/cursor.py
    • Refactored exception handling in the _fetch method to explicitly catch Aborted exceptions and ensure add_fetch_statement_for_retry is called correctly.
  • google/cloud/spanner_v1/metrics/metrics_exporter.py
    • Imported new constants for monitored resource labels.
    • Converted _resource_metrics_to_timeseries_pb from a static method to an instance method.
    • Added logic to ensure project_id is present in monitored resource labels and to filter out metrics missing instance_id to prevent API errors.
  • google/cloud/spanner_v1/pool.py
    • Replaced datetime.datetime.utcnow with a timezone-aware function datetime.datetime.now(datetime.timezone.utc) for current time retrieval.
  • google/cloud/spanner_v1/session.py
    • Imported timezone from datetime.
    • Updated _last_use_time initialization to use datetime.now(timezone.utc) for timezone awareness.
  • google/cloud/spanner_v1/snapshot.py
    • Modified _get_streamed_result_set to evaluate the first element of the iterator while holding a lock, ensuring the transaction ID is populated before the lock is released, addressing a race condition.
  • noxfile.py
    • Removed Python 3.9 from the list of unit test Python versions.
    • Removed 'unit-3.9' from the default Nox sessions.
  • pytest.ini
    • Added a new pytest marker noautofixt.
  • samples/samples/archived/backup_snippet.py
    • Imported timezone from datetime.
    • Updated datetime.utcnow() calls to datetime.now(timezone.utc) for timezone consistency.
    • Increased backup operation timeouts from 2100 to 3600 seconds.
    • Added a 10-minute timeout to while not operation.done() loops in cancel_backup and delete_backup.
  • samples/samples/archived/backup_snippet_test.py
    • Added a cmek_database pytest fixture.
    • Skipped CMEK-related tests due to missing KMS keys on the test project.
    • Updated test references from sample_database to cmek_database in skipped tests.
    • Modified create_sample_database fixture to delete associated backups during cleanup.
  • samples/samples/backup_sample.py
    • Imported timezone from datetime.
    • Updated datetime.utcnow() calls to datetime.now(timezone.utc) for timezone consistency.
    • Increased backup operation timeouts from 2100 to 3600 seconds.
    • Added a 10-minute timeout to while not operation.done() loops in cancel_backup and delete_backup.
  • samples/samples/backup_sample_test.py
    • Added a cmek_database pytest fixture.
    • Skipped CMEK-related tests due to missing KMS keys on the test project.
    • Updated test references from sample_database to cmek_database in skipped tests.
    • Modified create_sample_database fixture to delete associated backups during cleanup.
  • samples/samples/conftest.py
    • Adjusted cleanup logic in scrub_instance_ignore_not_found, sample_instance, and multi_region_instance fixtures to ensure databases are dropped after backups are deleted.
    • Added backup deletion logic to the create_sample_database fixture for proper resource cleanup.
  • samples/samples/noxfile.py
    • Removed Python versions 3.7, 3.8, and 3.9 from the ALL_VERSIONS list.
  • samples/samples/pg_snippets.py
    • Updated datetime.datetime.utcnow() calls to datetime.datetime.now(datetime.timezone.utc) for timezone consistency.
  • samples/samples/snippets.py
    • Updated datetime.datetime.utcnow() calls to datetime.datetime.now(datetime.timezone.utc) for timezone consistency.
    • Improved formatting for read_lock_mode_options_for_client and read_lock_mode arguments.
  • setup.py
    • Removed Python 3.9 from the programming language classifiers.
  • testing/constraints-3.9.txt
    • Removed the Python 3.9 specific constraints file.
  • tests/system/test_dbapi.py
    • Changed assertion for EXECUTE_BATCH_DML_METHOD count from == 3 to >= 3 for increased test flexibility.
    • Added pytest.warns context managers around _conn.commit() calls in autocommit mode to explicitly test non-operational behavior.
    • Updated datetime.datetime.utcnow().replace(tzinfo=UTC) to datetime.datetime.now(UTC) for timezone consistency.
  • tests/system/test_session_api.py
    • Wrapped a transaction.batch_update([]) test in a retry loop to handle Aborted exceptions more robustly.
    • Updated datetime.datetime.utcnow().replace(tzinfo=UTC) to datetime.datetime.now(UTC) for timezone consistency.
  • tests/unit/test__helpers.py
    • Renamed test_class to MockClass for clarity in unit tests.
  • tests/unit/test_backup.py
    • Updated datetime.datetime.utcnow() calls to datetime.datetime.now(UTC) or datetime.now(timezone.utc) for timezone consistency.
  • tests/unit/test_batch.py
    • Updated datetime.datetime.utcnow().replace(tzinfo=UTC) calls to datetime.datetime.now(UTC) for timezone consistency.
  • tests/unit/test_database.py
    • Updated datetime.datetime.utcnow().replace(tzinfo=UTC) calls to datetime.datetime.now(UTC) for timezone consistency.
  • tests/unit/test_instance.py
    • Updated datetime.datetime.utcnow().replace(tzinfo=UTC) to datetime.datetime.now(UTC) for timezone consistency.
  • tests/unit/test_metrics.py
    • Corrected a comment typo from # Copyright to # Copyright.
    • Renamed TestCredentials to MockCredentials for clarity.
  • tests/unit/test_pool.py
    • Imported timezone from datetime.
    • Updated datetime.utcnow() calls to datetime.now(timezone.utc) for timezone consistency.
    • Removed redundant import datetime statements.
    • Modified _Session constructor to use datetime.now(timezone.utc) as the default for last_use_time.
  • tests/unit/test_session.py
    • Updated datetime.datetime.utcnow().replace(tzinfo=UTC) calls to datetime.datetime.now(UTC) for timezone consistency.
  • tests/unit/test_spanner.py
    • Added import pytest.
    • Modified _execute_sql_helper and _read_helper to use deepcopy when creating _MockIterator via side_effect, ensuring fresh result sets for each call and preventing state issues.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/presubmit.yaml
Activity
  • The pull request description is a standard template and does not contain specific activity details or comments from reviewers or the author.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a critical fix for a race condition in streamed result sets by ensuring the transaction ID is populated before releasing the lock. It also includes several valuable improvements across the codebase, such as replacing the deprecated datetime.utcnow() with the timezone-aware datetime.now(timezone.utc), enhancing the robustness of samples and tests with timeouts and better cleanup logic, and fixing bugs in the metrics exporter. Additionally, support for Python 3.9 has been removed. The changes are well-implemented and improve the overall quality and stability of the library.

Note: Security Review did not run due to the size of the PR.

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

Labels

api: spanner Issues related to the googleapis/python-spanner API. samples Issues that are directly related to samples. size: l Pull request size is large.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants