Skip to content

feat: add send and ack mutations Cloud Spanner Queues - #17728

Merged
sakthivelmanii merged 9 commits into
googleapis:mainfrom
finnzzf:main
Sep 3, 2026
Merged

feat: add send and ack mutations Cloud Spanner Queues #17728
sakthivelmanii merged 9 commits into
googleapis:mainfrom
finnzzf:main

Conversation

@finnzzf

@finnzzf finnzzf commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

include unit and system tests

Fixes #17727

@finnzzf
finnzzf requested a review from a team as a code owner July 15, 2026 21:55

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

Copy link
Copy Markdown
Contributor

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 send and ack methods to both the async and sync Batch classes to support Cloud Spanner queues, along with corresponding unit and system tests. The feedback highlights that the unit tests incorrectly compare proto-plus message fields directly to raw Python values, which should be resolved by comparing protobuf messages using helper functions. Additionally, the system tests should be optimized to use the shared_instance fixture instead of creating and deleting new Spanner instances, and they should utilize pytest.skip() to properly report skipped tests when queues are not supported.

Comment thread packages/google-cloud-spanner/tests/unit/_async/test_batch.py
Comment thread packages/google-cloud-spanner/tests/unit/test_batch.py
Comment thread packages/google-cloud-spanner/tests/system/_async/test_database_api.py Outdated
Comment thread packages/google-cloud-spanner/tests/system/_async/test_database_api.py Outdated
Comment thread packages/google-cloud-spanner/tests/system/test_database_api.py Outdated
Comment thread packages/google-cloud-spanner/tests/system/test_database_api.py Outdated
Comment thread packages/google-cloud-spanner/tests/unit/_async/test_batch.py Outdated
Comment thread packages/google-cloud-spanner/tests/system/_async/test_database_api.py Outdated
Comment thread packages/google-cloud-spanner/tests/system/test_database_api.py Outdated
@parthea parthea added kokoro:force-run Add this label to force Kokoro to re-run the tests. kokoro:run Add this label to force Kokoro to re-run the tests. labels Jul 15, 2026
@yoshi-kokoro yoshi-kokoro removed kokoro:run Add this label to force Kokoro to re-run the tests. kokoro:force-run Add this label to force Kokoro to re-run the tests. labels Jul 15, 2026
@parthea
parthea requested a review from sinhasubham July 15, 2026 22:02
@parthea

parthea commented Jul 16, 2026

Copy link
Copy Markdown
Contributor
==================================== ERRORS ====================================
_________________ ERROR at setup of test_db_batch_send_and_ack _________________
file /tmpfs/src/github/google-cloud-python/packages/google-cloud-spanner/tests/system/_async/test_database_api.py, line 90
  @pytest.mark.asyncio
  async def test_db_batch_send_and_ack(not_emulator, spanner_client, database_dialect, instance_config):
      import uuid
      from google.cloud.spanner_admin_instance_v1.types import spanner_instance_admin
      from google.cloud.spanner_admin_database_v1 import DatabaseDialect
      from google.api_core.exceptions import MethodNotImplemented, GoogleAPIError

      instance_id = f"test-instance-{uuid.uuid4().hex[:8]}"
      db_name = f"test-db-{uuid.uuid4().hex[:8]}"
      queue_name = f"test_queue_{uuid.uuid4().hex[:8]}"

      config_name = instance_config.name
      request = spanner_instance_admin.CreateInstanceRequest(
          parent=spanner_client.project_name,
          instance_id=instance_id,
          instance=spanner_instance_admin.Instance(
              config=config_name,
              display_name=instance_id,
              node_count=1,
              edition=spanner_instance_admin.Instance.Edition.ENTERPRISE,
          ),
      )
      print(f"instance creation request: {request}")
      operation = await spanner_client.instance_admin_api.create_instance(request=request)
      operation.result(600)

      test_instance = spanner_client.instance(instance_id, configuration_name=config_name)

      try:
          test_database = await test_instance.database(db_name, database_dialect=database_dialect)
          operation = await test_database.create()
          operation.result(300)
          print("Database created successfully!")

          try:
              # 3. Create the Queue
              if database_dialect == DatabaseDialect.POSTGRESQL:
                  queue_ddl = f"""CREATE QUEUE {queue_name} (
                      id bigint NOT NULL,
                      "Payload" varchar NOT NULL,
                      PRIMARY KEY (id)
                  )"""
              else:
                  queue_ddl = f"""CREATE QUEUE {queue_name} (
                      Id INT64 NOT NULL,
                      Payload STRING(MAX) NOT NULL
                  ) PRIMARY KEY (Id)"""

              try:
                  operation = await test_database.update_ddl([queue_ddl])
                  await operation.result(600)
              except MethodNotImplemented as e:
                  print(f"MethodNotImplemented. Skipping test because Queues are not implemented yet: {e}")
                  return
              except GoogleAPIError as e:
                  if getattr(e, 'code', None) == 501 or (getattr(e, 'grpc_status_code', None) and e.grpc_status_code.name == 'UNIMPLEMENTED') or "UNIMPLEMENTED" in str(e):
                      print(f"Skipping test because Queues are not implemented yet: {e}")
                      return
                  raise
              print("Queue created successfully.")

              # 4. Run mutations
              print("Sending message to queue...")
              async with test_database.batch() as batch:
                  batch.send(
                      queue=queue_name,
                      key=(2,),
                      payload="Hello, Queues!",
                  )
              print("Send successful.")

              print("Acking message in queue...")
              async with test_database.batch() as batch:
                  batch.ack(
                      queue=queue_name,
                      key=(2,),
                  )
              print("Ack successful.")

          finally:
              print("Dropping database...")
              await test_database.drop()
      finally:
          print("Dropping instance...")
          await test_instance.delete()
E       fixture 'not_emulator' not found
>       available fixtures: _asyncio_loop_factory, _class_scoped_runner, _function_scoped_runner, _module_scoped_runner, _package_scoped_runner, _session_scoped_runner, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, capteesys, database_dialect, database_operation_timeout, databases_to_delete, doctest_namespace, event_loop_policy, instance_config, instance_configs, instance_operation_timeout, monkeypatch, not_postgres, proto_descriptor_file, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, reset_cached_apis, shared_database, shared_instance, shared_instance_id, spanner_client, subtests, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, unused_tcp_port, unused_tcp_port_factory, unused_udp_port, unused_udp_port_factory
>       use 'pytest --fixtures [testpath]' for help on them.

@sakthivelmanii sakthivelmanii added the kokoro:force-run Add this label to force Kokoro to re-run the tests. label Aug 3, 2026
@yoshi-kokoro yoshi-kokoro removed the kokoro:force-run Add this label to force Kokoro to re-run the tests. label Aug 3, 2026
@parthea parthea added kokoro:force-run Add this label to force Kokoro to re-run the tests. kokoro:run Add this label to force Kokoro to re-run the tests. labels Aug 4, 2026
@yoshi-kokoro yoshi-kokoro removed kokoro:run Add this label to force Kokoro to re-run the tests. kokoro:force-run Add this label to force Kokoro to re-run the tests. labels Aug 4, 2026
@sinhasubham

Copy link
Copy Markdown
Contributor

/gemini review

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

Copy link
Copy Markdown
Contributor

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 support for Cloud Spanner Queues by adding send and ack methods to the Batch class in both synchronous and asynchronous modules, along with corresponding unit and system tests. Feedback on these changes suggests removing an accidentally committed scratchpad file (test_spanner.py), switching the instance edition in system tests from ENTERPRISE_PLUS to ENTERPRISE to minimize testing costs, and safely retrieving the gRPC status code name using getattr in system tests to prevent potential AttributeErrors.

Comment thread packages/google-cloud-spanner/test_spanner.py Outdated
Comment thread packages/google-cloud-spanner/tests/system/_async/conftest.py Outdated
Comment thread packages/google-cloud-spanner/tests/system/conftest.py Outdated
Comment thread packages/google-cloud-spanner/tests/system/test_database_api.py
Comment thread packages/google-cloud-spanner/test_spanner.py Outdated
@sinhasubham

Copy link
Copy Markdown
Contributor

/gemini review

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

Copy link
Copy Markdown
Contributor

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 send and ack methods to both the synchronous and asynchronous Batch classes to support Cloud Spanner queue mutations, along with corresponding unit and system tests. The review feedback identifies a critical issue in the async system test where a coroutine is not awaited, and suggests moving the database creation checks inside the try blocks of both sync and async tests to guarantee that the database is dropped in the finally block in case of failure.

Comment thread packages/google-cloud-spanner/tests/system/_async/test_database_api.py Outdated
Comment thread packages/google-cloud-spanner/tests/system/test_database_api.py Outdated
@snippet-bot

snippet-bot Bot commented Aug 25, 2026

Copy link
Copy Markdown

Here is the summary of changes.

You are about to add 9 region tags.

This comment is generated by snippet-bot.
If you find problems with this result, please file an issue at:
https://github.com/googleapis/repo-automation-bots/issues.
To update this comment, add snippet-bot:force-run label or use the checkbox below:

  • Refresh this comment

@sakthivelmanii sakthivelmanii added the kokoro:force-run Add this label to force Kokoro to re-run the tests. label Aug 27, 2026
@yoshi-kokoro yoshi-kokoro removed the kokoro:force-run Add this label to force Kokoro to re-run the tests. label Aug 27, 2026
@sakthivelmanii sakthivelmanii added the kokoro:force-run Add this label to force Kokoro to re-run the tests. label Aug 31, 2026
@yoshi-kokoro yoshi-kokoro removed the kokoro:force-run Add this label to force Kokoro to re-run the tests. label Aug 31, 2026
@sakthivelmanii sakthivelmanii added the kokoro:force-run Add this label to force Kokoro to re-run the tests. label Sep 3, 2026
@sakthivelmanii
sakthivelmanii enabled auto-merge (squash) September 3, 2026 04:30
@yoshi-kokoro yoshi-kokoro removed the kokoro:force-run Add this label to force Kokoro to re-run the tests. label Sep 3, 2026
@sakthivelmanii
sakthivelmanii merged commit 182ff9f into googleapis:main Sep 3, 2026
46 checks passed
@release-please release-please Bot mentioned this pull request Sep 3, 2026
noahdietz pushed a commit that referenced this pull request Sep 3, 2026
🤖 I have created a release *beep* *boop*
---


<details><summary>django-google-spanner: 5.1.0</summary>

##
[5.1.0](django-google-spanner-v5.0.1...django-google-spanner-v5.1.0)
(2026-09-03)


### Features

* **django-google-spanner:** support Django 6.0
([#18128](#18128))
([207d947](207d947))
</details>

<details><summary>google-ads-admanager: 0.10.3</summary>

##
[0.10.3](google-ads-admanager-v0.10.2...google-ads-admanager-v0.10.3)
(2026-09-03)


### Features

* update googleapis and regenerate
([#18229](#18229))
([d4f8a57](d4f8a57))
</details>

<details><summary>google-api-core: 2.36.0</summary>

##
[2.36.0](google-api-core-v2.35.0...google-api-core-v2.36.0)
(2026-09-03)


### Features

* **api-core:** add ClientInterceptor and apply_interceptors helper (A)
([#18236](#18236))
([b6db5a9](b6db5a9))
* **api-core:** add tracer_provider to ClientOptions for OTel support
([#18139](#18139))
([9ffebc2](9ffebc2))


### Bug Fixes

* **api-core:** handle list-shaped REST error payloads
([#18232](#18232))
([02d1fd8](02d1fd8))
* **api-core:** move http encoding into transcode method
([#18218](#18218))
([082a99a](082a99a))
</details>

<details><summary>google-cloud-batch: 0.22.3</summary>

##
[0.22.3](google-cloud-batch-v0.22.2...google-cloud-batch-v0.22.3)
(2026-09-03)


### Features

* update API sources and regenerate
([#18267](#18267))
([813a5c1](813a5c1))
</details>

<details><summary>google-cloud-biglake-hive: 0.3.3</summary>

##
[0.3.3](google-cloud-biglake-hive-v0.3.2...google-cloud-biglake-hive-v0.3.3)
(2026-09-03)


### Features

* **google/cloud/biglake/hive/v1:** onboard a new library
([#18172](#18172))
([97668d8](97668d8))
</details>

<details><summary>google-cloud-bigquery: 3.45.0</summary>

##
[3.45.0](google-cloud-bigquery-v3.44.0...google-cloud-bigquery-v3.45.0)
(2026-09-03)


### Features

* add user-agent delegation telemetry for pandas-gbq
([#18184](#18184))
([85ddfe5](85ddfe5))
</details>

<details><summary>google-cloud-bigquery-migration: 0.15.1</summary>

##
[0.15.1](google-cloud-bigquery-migration-v0.15.0...google-cloud-bigquery-migration-v0.15.1)
(2026-09-03)


### Features

* update API sources and regenerate
([#18267](#18267))
([813a5c1](813a5c1))
</details>

<details><summary>google-cloud-bigquery-reservation: 1.27.0</summary>

##
[1.27.0](google-cloud-bigquery-reservation-v1.26.0...google-cloud-bigquery-reservation-v1.27.0)
(2026-09-03)


### Features

* update googleapis and regenerate
([#18229](#18229))
([d4f8a57](d4f8a57))
</details>

<details><summary>google-cloud-bigtable: 2.44.0</summary>

##
[2.44.0](google-cloud-bigtable-v2.43.0...google-cloud-bigtable-v2.44.0)
(2026-09-03)


### Features

* **bigtable:** Rerouted CheckAndMutateRows and ReadModifyWriteRows to
data client
([#18190](#18190))
([990f86e](990f86e))
* **bigtable:** Rerouted DirectRow.commit to use mutate_row
([#18191](#18191))
([7126a54](7126a54))
* update API sources and regenerate
([#18267](#18267))
([813a5c1](813a5c1))
</details>

<details><summary>google-cloud-compute: 1.52.0</summary>

##
[1.52.0](google-cloud-compute-v1.51.0...google-cloud-compute-v1.52.0)
(2026-09-03)


### Features

* update googleapis and regenerate
([#18229](#18229))
([d4f8a57](d4f8a57))
</details>

<details><summary>google-cloud-compute-v1beta: 0.12.3</summary>

##
[0.12.3](google-cloud-compute-v1beta-v0.12.2...google-cloud-compute-v1beta-v0.12.3)
(2026-09-03)


### Features

* update googleapis and regenerate
([#18229](#18229))
([d4f8a57](d4f8a57))
</details>

<details><summary>google-cloud-confidentialcomputing: 0.11.1</summary>

##
[0.11.1](google-cloud-confidentialcomputing-v0.11.0...google-cloud-confidentialcomputing-v0.11.1)
(2026-09-03)


### Features

* update API sources and regenerate
([#18267](#18267))
([813a5c1](813a5c1))
</details>

<details><summary>google-cloud-config: 0.7.1</summary>

##
[0.7.1](google-cloud-config-v0.7.0...google-cloud-config-v0.7.1)
(2026-09-03)


### Features

* update googleapis and regenerate
([#18229](#18229))
([d4f8a57](d4f8a57))
</details>

<details><summary>google-cloud-container: 2.66.0</summary>

##
[2.66.0](google-cloud-container-v2.65.0...google-cloud-container-v2.66.0)
(2026-09-03)


### Features

* update googleapis and regenerate
([#18229](#18229))
([d4f8a57](d4f8a57))
</details>

<details><summary>google-cloud-discoveryengine: 0.20.3</summary>

##
[0.20.3](google-cloud-discoveryengine-v0.20.2...google-cloud-discoveryengine-v0.20.3)
(2026-09-03)


### Features

* update googleapis and regenerate
([#18229](#18229))
([d4f8a57](d4f8a57))
</details>

<details><summary>google-cloud-dlp: 3.39.0</summary>

##
[3.39.0](google-cloud-dlp-v3.38.0...google-cloud-dlp-v3.39.0)
(2026-09-03)


### Features

* update API sources and regenerate
([#18267](#18267))
([813a5c1](813a5c1))
</details>

<details><summary>google-cloud-firestore: 2.30.0</summary>

##
[2.30.0](google-cloud-firestore-v2.29.0...google-cloud-firestore-v2.30.0)
(2026-09-03)


### Features

* **firestore:** configure gRPC message length limits for large
documents
([#18220](#18220))
([6e0f1d9](6e0f1d9))
</details>

<details><summary>google-cloud-geminidataanalytics: 0.13.2</summary>

##
[0.13.2](google-cloud-geminidataanalytics-v0.13.1...google-cloud-geminidataanalytics-v0.13.2)
(2026-09-03)


### Features

* update API sources and regenerate
([#18267](#18267))
([813a5c1](813a5c1))
</details>

<details><summary>google-cloud-pubsub: 2.40.0</summary>

##
[2.40.0](google-cloud-pubsub-v2.39.2...google-cloud-pubsub-v2.40.0)
(2026-09-03)


### Features

* update googleapis and regenerate
([#18229](#18229))
([d4f8a57](d4f8a57))
</details>

<details><summary>google-cloud-spanner: 3.71.0</summary>

##
[3.71.0](google-cloud-spanner-v3.70.0...google-cloud-spanner-v3.71.0)
(2026-09-03)


### Features

* add send and ack mutations Cloud Spanner Queues
([#17728](#17728))
([182ff9f](182ff9f)),
refs
[#17727](#17727)
</details>

<details><summary>google-cloud-storage-control: 1.15.0</summary>

##
[1.15.0](google-cloud-storage-control-v1.14.0...google-cloud-storage-control-v1.15.0)
(2026-09-03)


### Features

* update googleapis and regenerate
([#18229](#18229))
([d4f8a57](d4f8a57))
</details>

<details><summary>google-developer-knowledge: 0.1.2</summary>

##
[0.1.2](google-developer-knowledge-v0.1.1...google-developer-knowledge-v0.1.2)
(2026-09-03)


### Features

* update API sources and regenerate
([#18267](#18267))
([813a5c1](813a5c1))
* update googleapis and regenerate
([#18229](#18229))
([d4f8a57](d4f8a57))
</details>

<details><summary>google-maps-areainsights: 0.5.1</summary>

##
[0.5.1](google-maps-areainsights-v0.5.0...google-maps-areainsights-v0.5.1)
(2026-09-03)


### Features

* update googleapis and regenerate
([#18229](#18229))
([d4f8a57](d4f8a57))
</details>

<details><summary>google-maps-mapmanagement: 0.1.1</summary>

##
[0.1.1](google-maps-mapmanagement-v0.1.0...google-maps-mapmanagement-v0.1.1)
(2026-09-03)


### Features

* **google/maps/mapmanagement/v2:** onboard a new library
([#18173](#18173))
([f0f214b](f0f214b))
</details>

<details><summary>google-maps-routing: 0.11.1</summary>

##
[0.11.1](google-maps-routing-v0.11.0...google-maps-routing-v0.11.1)
(2026-09-03)


### Features

* update googleapis and regenerate
([#18229](#18229))
([d4f8a57](d4f8a57))
</details>

<details><summary>googleapis-common-protos: 1.75.3</summary>

##
[1.75.3](googleapis-common-protos-v1.75.2...googleapis-common-protos-v1.75.3)
(2026-09-03)


### Bug Fixes

* **googleapis-common-protos:** remove deprecated license classifier
([#18242](#18242))
([6f0216a](6f0216a)),
refs
[#18235](#18235)
</details>

<details><summary>sqlalchemy-spanner: 1.20.1</summary>

##
[1.20.1](sqlalchemy-spanner-v1.20.0...sqlalchemy-spanner-v1.20.1)
(2026-09-03)


### Bug Fixes

* **sqlalchemy-spanner:** robust session-isolated test databases and
clean lifecycle management
([#18179](#18179))
([3e0bda4](3e0bda4))


### Documentation

* **sqlalchemy-spanner:** centralize CONTRIBUTING.rst pointers
([#18142](#18142))
([f55ae02](f55ae02))
</details>

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cloud-spanner-queue: add python mutation support

5 participants