Skip to content

feat(Spanner): Add support for Cloud Queues - #15850

Open
efevans wants to merge 22 commits into
googleapis:mainfrom
efevans:spanner-queues
Open

efevans wants to merge 22 commits into
googleapis:mainfrom
efevans:spanner-queues

Conversation

@efevans

@efevans efevans commented Aug 21, 2026 •

Copy link
Copy Markdown
Contributor

b/422231498

Suggested path for reviewing

  1. Take a look at the doc describing public surface changes, link to it in the issue. You can skip the Background section and focus on the others.
  2. Peek at the public Send and Ack methods in SpannerConnection.cs, and then look at the first test of QueueTests.cs` in the integration test project to see a basic usage.
  3. Look at the changes big block change in SpannerCommand.ExecutableCommand around lines 400. This is the portion of code that packages the Send and Ack mutations into the protobuf message wire type
  4. The remainder of the code is simple enough and is largely wiring up the CreateSendCommand public method down to the part that prepares the mutation protobuf types from above

DMN until squash

@product-auto-label product-auto-label Bot added the api: spanner Issues related to the Spanner API. label Aug 21, 2026

@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 Spanner queues by adding Send and Ack command types, updating the command builder and connection classes, and introducing queue-related test fixtures and integration tests. Feedback on the changes highlights syntax errors in the queue creation SQL statement, an integration test that defines commands but never executes or disposes of them, and a public field that should be private and readonly. Additionally, there is a copy-paste error in the XML documentation for CreateSendCommand, and a potential NullReferenceException in a SpannerCommand constructor because the null check on key is executed after the constructor initializer.

Comment thread apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data/SpannerConnection.cs Outdated
Comment thread apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data/SpannerCommand.cs Outdated
@efevans
efevans force-pushed the spanner-queues branch 16 times, most recently from 6fde46a to d858058 Compare August 26, 2026 21:22
@efevans

efevans commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

/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 Spanner Queues by adding Send and Ack commands, updating SpannerCommand and SpannerConnection to handle queue operations, and adding integration tests. The review feedback highlights several issues to address, including a syntax error from a trailing comma in the CREATE QUEUE DDL, a code smell from calling an abstract method in a constructor, timezone-related issues from using DateTime.Now instead of DateTime.UtcNow, hardcoded personal test configurations, a potential NullReferenceException when validating Payload, and various copy-paste errors in exception messages and XML documentation.

Comment thread apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data/SpannerConnection.cs Outdated
Comment thread apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data/SpannerConnection.cs Outdated
@googleapis googleapis deleted a comment from gemini-code-assist Bot Aug 27, 2026
@efevans
efevans force-pushed the spanner-queues branch 2 times, most recently from 085d8cc to e83cef5 Compare August 27, 2026 17:01
@efevans

efevans commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

/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 Spanner queues by adding 'Send' and 'Ack' command types to SpannerCommand, along with corresponding integration tests and fixtures. The review feedback highlights several critical issues and improvement opportunities: a syntax error (trailing comma) in the queue creation DDL, synchronous blocking in the test fixture setup, a lack of validation for single-key constraints on Send and Ack commands, a potential runtime failure when validating inferred payload types, and missing property copies in the SpannerCommand copy constructor which would break cloning.

Comment thread apis/Google.Cloud.Spanner.Data/Google.Cloud.Spanner.Data/SpannerCommand.cs Outdated
@efevans
efevans force-pushed the spanner-queues branch 2 times, most recently from f2a5bc7 to e848450 Compare August 27, 2026 19:25
@efevans

efevans commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

/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 Spanner database queues by adding Send and Ack command types, along with corresponding connection helper methods, test fixtures, and unit/integration tests. However, there are critical issues in the implementation: the state checks validating that exactly one key is provided for Send and Ack mutations are inverted, which will cause runtime failures when valid inputs are provided. Additionally, a trailing comma in the CREATE QUEUE DDL statement in MutationsQueueFixture.cs will result in a syntax error at runtime.

@efevans
efevans removed the request for review from amanda-tarafa September 17, 2026 22:34
@efevans

efevans commented Sep 17, 2026

Copy link
Copy Markdown
Contributor Author

@amanda-tarafa removing you to try cutting down noise until this is ready for review again

@efevans
efevans marked this pull request as ready for review September 21, 2026 21:23
@efevans efevans added the do not merge Indicates a pull request not ready for merge, due to either quality or timing. label Sep 24, 2026

@amanda-tarafa amanda-tarafa 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.

Only partially reviewed, but better to get the changes I request in before continuing. These are bound to change things further own.

/// </summary>
/// <param name="databaseQueue">The name of the queue to send a message to. Must not be null.</param>
/// <param name="parameters">A collection of <see cref="SpannerParameter"/> that comprise
/// the message key and Payload. Requires a Payload and at least one non-payload parameter.</param>

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.

Do we need to validate that the key is present? Even if it's required by Spanner, if there's nothing and we set it to nothing, then Spanner will fail.

And actually, we can do that for Payload as well, we attempt to extract payload, but if it's not there, we just set it to nothin and let Spanner fail.

Yes, I think this approach matches better our philosophy of keeping validations to a minimum client side. And when you make these changes, make sure to update this comment here to say something like "A collection of parameters that should contain the key elements and the payload."

And same for the other.

Comment on lines +198 to +209
internal static SpannerCommand ForSendCommand(
SpannerCommandTextBuilder commandTextBuilder,
SpannerConnection connection,
SpannerParameterCollection parameters,
SpannerTransaction transaction = null) => new(commandTextBuilder, connection, transaction, parameters);

internal static SpannerCommand ForAckCommand(
SpannerCommandTextBuilder commandTextBuilder,
SpannerConnection connection,
SpannerParameterCollection parameters,
SpannerTransaction transaction = null) => new(commandTextBuilder, connection, transaction, parameters);

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.

Why do we add this layer here that we don't have for any of the other commands. Let's just use the SpannerCommand constructor anywhere when we create send and ack.

Comment on lines +169 to +170
/// Note: "Insert" and "Delete" are never treated as Send and Ack even when the
/// target table is internally a queue.

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.

Suggested change
/// Note: "Insert" and "Delete" are never treated as Send and Ack even when the
/// target table is internally a queue.
/// Note: `insert <name>` and `delete <name>` are always interpreted as insert and delete mutations, never as send or ack mutations.

Comment on lines +373 to +382
/// <summary>
/// Optional configurations for Send mutations.
/// </summary>
public SendOptions SendOptions { get; set; }

/// <summary>
/// Optional configurations for Ack mutations.
/// </summary>
public AckOptions AckOptions { get; set; }

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.

In docs, add a note, like the one we have in DirectedRead for instance, saying that these will be ignored for all other operations.

Comment on lines +268 to +269
/// Note: Insert and Delete are never treated as Send and Ack even when the
/// target table is internally a queue.

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.

Same wording as in the other one.

Comment on lines +35 to +36
private const string SendCommand = "SEND";
private const string AckCommand = "ACK";

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.

We are not parsing these, so why do we need these constants for? We cannot represent these as text, we should use the empty string for the text command here, similar to what we do for Read IIRC.

/// <param name="queue">The name of the Spanner database queue for which messages will be acked. Must not be null.</param>
/// <returns>A <see cref="SpannerCommandTextBuilder"/> representing a <see cref="F:SpannerCommandType.Ack"/> Spanner command.</returns>
public static SpannerCommandTextBuilder CreateAckTextBuilder(string queue) =>
CreateBuilderForTableDml(AckCommand, SpannerCommandType.Ack, queue);

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.

I think you need to create a new method CreateBuilderForQueueMutation that only receives the type and the name of the queue. We need to add a new public property here called TargetQueue that's equivalent to TargetTable but only one of those can be set at any given time.

This branch has not been deployed

No deployments
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 Spanner API. do not merge Indicates a pull request not ready for merge, due to either quality or timing.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants