Skip to content

feat(spannerlib): support statement cancellation via Cancel#833

Open
olavloite wants to merge 2 commits into
mainfrom
fix/585-cancel-support
Open

feat(spannerlib): support statement cancellation via Cancel#833
olavloite wants to merge 2 commits into
mainfrom
fix/585-cancel-support

Conversation

@olavloite

@olavloite olavloite commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

Adds a package-level and connection-level Cancel function to Spanner Lib. This wraps statement execution contexts in a cancellable context and manages the cancel function lifecycle. Active query contexts are kept alive for the duration of the result set (rows) reading and automatically released upon rows closure.

Fixes #585

@olavloite olavloite requested a review from a team as a code owner June 11, 2026 15:58

@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 the ability to cancel currently running statements on a connection by adding a Cancel function, tracking active cancel functions in the Connection struct, and updating Execute and ExecuteBatch to support cancellation. A review comment points out that Cancel() currently only cancels conn.cancelActive, which is cleared once Execute() returns. To ensure cancellation works during row streaming, it is recommended to also iterate over and cancel active results in conn.results.

Comment on lines +380 to +386
func (conn *Connection) Cancel() {
conn.mu.Lock()
defer conn.mu.Unlock()
if conn.cancelActive != nil {
conn.cancelActive()
}
}

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.

high

Currently, Cancel() only cancels conn.cancelActive, which is cleared via defer conn.clearActiveCancel() as soon as Execute() returns. This means that once the query execution completes and row streaming begins, calling Cancel() will be a no-op and will not cancel the active query/rows context.

To ensure that Cancel() can also cancel active queries during row streaming, we should also iterate over and cancel any active results in conn.results.

func (conn *Connection) Cancel() {
	conn.mu.Lock()
	defer conn.mu.Unlock()
	if conn.cancelActive != nil {
		conn.cancelActive()
	}
	if conn.results != nil {
		conn.results.Range(func(key, value interface{}) bool {
			if r, ok := value.(*rows); ok {
				if r.cancel != nil {
					r.cancel()
				}
			}
			return true
		})
	}
}

@olavloite

Copy link
Copy Markdown
Collaborator Author

LGTM. This adds Cancel support to the FFI spannerlib API, allowing client wrappers to cancel active statement executions. The mutex locking and context lifecycle are implemented cleanly, and the test coverage is correct.

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.

Support Cancel method in Spanner Lib

1 participant