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 googleapis/python-spanner#269) |
request_priority added to pre_exec() |
| Jan 2023 |
5bd5076 (PR googleapis/python-spanner#494) |
transaction_tag and request_tag added to pre_exec() |
| Jun 2023 |
66c32a4 (PR googleapis/python-spanner#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:
- Read
self.execution_options.get("timeout")
- Set
self._dbapi_connection.connection.timeout = timeout
- Reset
timeout to None in reset_connection()
Files changed
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: #16492
Related
Summary
The SQLAlchemy Spanner dialect does not handle
timeoutinexecution_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. Thetimeoutoption is not handled.The dialect's
reset_connection()method resetsread_only,staleness,request_priority,transaction_tag, andrequest_tagon the DBAPI connection when returning connections to the pool.timeoutis not reset.Timeline
pre_exec()handlesread_onlyandstalenessd976fda(PR googleapis/python-spanner#269)request_priorityadded topre_exec()5bd5076(PR googleapis/python-spanner#494)transaction_tagandrequest_tagadded topre_exec()66c32a4(PR googleapis/python-spanner#503)ignore_transaction_warningsadded topre_exec()timeoutwas never added topre_exec()orreset_connection()Each new execution option was added incrementally.
timeoutwas not included in any of these additions.Proposed Change
Add
timeouthandling toSpannerExecutionContext.pre_exec()following the existing pattern forrequest_priority:self.execution_options.get("timeout")self._dbapi_connection.connection.timeout = timeouttimeouttoNoneinreset_connection()Files changed
google/cloud/sqlalchemy_spanner/sqlalchemy_spanner.py— Addtimeouthandling topre_exec()andreset_connection()Usage
Prerequisites
This change depends on the DBAPI
Connectionsupporting atimeoutproperty: #16492Related
_SnapshotBase.execute_sql()has acceptedtimeout=since November 2018 (PR [Spanner] Add timeout + retry settings to Sessions/Snapshots #6536 in the original monorepo)googleapis/python-spanner-sqlalchemy(now archived) and moved togoogleapis/google-cloud-python/packages/sqlalchemy-spanner