Skip to content

feat(sqlalchemy-spanner): wire timeout execution option through to DBAPI Connection.timeout #16467

@waiho-gumloop

Description

@waiho-gumloop

Summary

The SQLAlchemy Spanner dialect does not handle timeout in execution_options. Users cannot set a per-statement gRPC deadline through SQLAlchemy, causing all queries to use the gRPC default timeout of 3600 seconds.

Background

The Spanner SQLAlchemy dialect (SpannerExecutionContext.pre_exec()) reads execution options and forwards them to the DBAPI connection. Currently handled options: read_only, staleness, request_priority, transaction_tag, request_tag. The timeout option is not handled.

The dialect's reset_connection() method resets read_only, staleness, request_priority, transaction_tag, and request_tag on the DBAPI connection when returning connections to the pool. timeout is not reset.

Timeline

Date Commit Event
Apr 2020 Initial commit Dialect created — pre_exec() handles read_only and staleness
Oct 2021 d976fda (PR #269) request_priority added to pre_exec()
Jan 2023 5bd5076 (PR #494) transaction_tag and request_tag added to pre_exec()
Jun 2023 66c32a4 (PR #503) ignore_transaction_warnings added to pre_exec()
None N/A timeout was never added to pre_exec() or reset_connection()

Each new execution option was added incrementally. timeout was not included in any of these additions.

Proposed Change

Add timeout handling to SpannerExecutionContext.pre_exec() following the existing pattern for request_priority:

  1. Read self.execution_options.get("timeout")
  2. Set self._dbapi_connection.connection.timeout = timeout
  3. Reset timeout to None in reset_connection()

Files changed

  1. google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py — Add timeout handling to pre_exec() and reset_connection()

Usage

from sqlalchemy import create_engine

engine = create_engine("spanner:///...")

# Per-connection timeout
with engine.connect().execution_options(timeout=60) as conn:
    conn.execute(text("SELECT * FROM my_table"))

# Engine-level default timeout
engine = create_engine("spanner:///...", execution_options={"timeout": 60})

Prerequisites

This change depends on the DBAPI Connection supporting a timeout property: googleapis/python-spanner#1534

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions