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
fromsqlalchemyimportcreate_engineengine=create_engine("spanner:///...")
# Per-connection timeoutwithengine.connect().execution_options(timeout=60) asconn:
conn.execute(text("SELECT * FROM my_table"))
# Engine-level default timeoutengine=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