Skip to content

Commit fdc9409

Browse files
Document per-RPC-phase timeout budget on connection and pool docstrings
The timeout parameter is applied per RPC phase (send, read, any continuation drain), not as an end-to-end deadline. The wire layer's _operation_deadline already documented this correctly, but the public DqliteConnection / AsyncDqliteConnection / ConnectionPool / create_pool docstrings just said "Connection timeout in seconds" — letting an operator size their wait_for() expecting the inner budget to be absolute. Spell out the per-phase semantics and direct callers to wrap with asyncio.timeout() for a wall-clock deadline. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 6c3d2af commit fdc9409

3 files changed

Lines changed: 23 additions & 4 deletions

File tree

src/dqliteclient/__init__.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@ async def connect(
7070
Args:
7171
address: Node address in "host:port" format
7272
database: Database name to open
73-
timeout: Connection timeout in seconds
73+
timeout: Per-RPC-phase timeout in seconds (forwarded). Each
74+
phase of an operation gets the full budget independently;
75+
wrap with ``asyncio.timeout(...)`` to enforce an end-to-end
76+
deadline.
7477
max_total_rows: Cumulative row cap across continuation frames
7578
for a single query. Forwarded to the underlying
7679
DqliteConnection. None disables the cap.
@@ -124,7 +127,10 @@ async def create_pool(
124127
database: Database name to open
125128
min_size: Minimum number of connections to maintain
126129
max_size: Maximum number of connections
127-
timeout: Connection timeout in seconds
130+
timeout: Per-RPC-phase timeout in seconds (forwarded). Each
131+
phase of an operation gets the full budget independently;
132+
wrap with ``asyncio.timeout(...)`` to enforce an end-to-end
133+
deadline.
128134
cluster: Externally-owned ClusterClient shared across pools.
129135
node_store: Externally-owned NodeStore used to build a new
130136
ClusterClient. Mutually exclusive with ``cluster``.

src/dqliteclient/connection.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,14 @@ def __init__(
509509
Args:
510510
address: Node address in "host:port" format
511511
database: Database name to open
512-
timeout: Connection timeout in seconds
512+
timeout: Per-RPC-phase timeout in seconds. The same budget
513+
is applied to each phase of an operation independently
514+
(send, then read, then any continuation drain), so a
515+
single high-level call (e.g. a ``query_sql`` returning
516+
a large continuation-paginated result) can take up to
517+
roughly N × ``timeout`` end-to-end. To enforce a true
518+
end-to-end deadline, wrap the call in
519+
``asyncio.timeout(...)`` or ``asyncio.wait_for(...)``.
513520
max_total_rows: Cumulative row cap across continuation
514521
frames for a single query. Prevents a slow-drip server
515522
from keeping the client alive indefinitely within the

src/dqliteclient/pool.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,13 @@ def __init__(
140140
database: Database name
141141
min_size: Minimum connections to maintain
142142
max_size: Maximum connections allowed
143-
timeout: Connection timeout
143+
timeout: Per-RPC-phase timeout (forwarded to each pooled
144+
``DqliteConnection``). Each phase of an operation
145+
(send, read, any continuation drain) gets the full
146+
budget independently, so a single call can take up to
147+
roughly N × ``timeout`` end-to-end. Wrap callers in
148+
``asyncio.timeout(...)`` to enforce a wall-clock
149+
deadline.
144150
cluster: Externally-owned ClusterClient. Lets multiple pools
145151
share one ClusterClient (and thus its node store, leader
146152
cache, etc.) across databases or tenants.

0 commit comments

Comments
 (0)