7
7
from __future__ import annotations
8
8
9
9
import asyncio
10
- from collections .abc import Awaitable , Callable
11
10
import functools
12
11
import inspect
13
12
import logging
14
13
import time
14
+ import warnings
15
+ from collections .abc import Awaitable , Callable
15
16
from types import TracebackType
16
17
from typing import Any , Optional , Type
17
- import warnings
18
-
19
- from . import compat
20
- from . import connection
21
- from . import exceptions
22
- from . import protocol
23
18
19
+ from . import compat , connection , exceptions , protocol
24
20
25
21
logger = logging .getLogger (__name__ )
26
22
@@ -338,27 +334,46 @@ class Pool:
338
334
"""
339
335
340
336
__slots__ = (
341
- '_queue' , '_loop' , '_minsize' , '_maxsize' ,
342
- '_init' , '_connect' , '_reset' , '_connect_args' , '_connect_kwargs' ,
343
- '_holders' , '_initialized' , '_initializing' , '_closing' ,
344
- '_closed' , '_connection_class' , '_record_class' , '_generation' ,
345
- '_setup' , '_max_queries' , '_max_inactive_connection_lifetime'
337
+ "_queue" ,
338
+ "_loop" ,
339
+ "_minsize" ,
340
+ "_maxsize" ,
341
+ "_init" ,
342
+ "_connect" ,
343
+ "_reset" ,
344
+ "_connect_args" ,
345
+ "_connect_kwargs" ,
346
+ "_holders" ,
347
+ "_initialized" ,
348
+ "_initializing" ,
349
+ "_closing" ,
350
+ "_closed" ,
351
+ "_connection_class" ,
352
+ "_record_class" ,
353
+ "_generation" ,
354
+ "_setup" ,
355
+ "_max_queries" ,
356
+ "_max_inactive_connection_lifetime" ,
357
+ "_pool_timeout" ,
346
358
)
347
359
348
- def __init__ (self , * connect_args ,
349
- min_size ,
350
- max_size ,
351
- max_queries ,
352
- max_inactive_connection_lifetime ,
353
- connect = None ,
354
- setup = None ,
355
- init = None ,
356
- reset = None ,
357
- loop ,
358
- connection_class ,
359
- record_class ,
360
- ** connect_kwargs ):
361
-
360
+ def __init__ (
361
+ self ,
362
+ * connect_args ,
363
+ min_size ,
364
+ max_size ,
365
+ max_queries ,
366
+ max_inactive_connection_lifetime ,
367
+ pool_timeout = None ,
368
+ connect = None ,
369
+ setup = None ,
370
+ init = None ,
371
+ reset = None ,
372
+ loop ,
373
+ connection_class ,
374
+ record_class ,
375
+ ** connect_kwargs ,
376
+ ):
362
377
if len (connect_args ) > 1 :
363
378
warnings .warn (
364
379
"Passing multiple positional arguments to asyncpg.Pool "
@@ -389,6 +404,11 @@ def __init__(self, *connect_args,
389
404
'max_inactive_connection_lifetime is expected to be greater '
390
405
'or equal to zero' )
391
406
407
+ if pool_timeout is not None and pool_timeout <= 0 :
408
+ raise ValueError (
409
+ "pool_timeout is expected to be greater than zero or None"
410
+ )
411
+
392
412
if not issubclass (connection_class , connection .Connection ):
393
413
raise TypeError (
394
414
'connection_class is expected to be a subclass of '
@@ -423,8 +443,10 @@ def __init__(self, *connect_args,
423
443
self ._reset = reset
424
444
425
445
self ._max_queries = max_queries
426
- self ._max_inactive_connection_lifetime = \
446
+ self ._max_inactive_connection_lifetime = (
427
447
max_inactive_connection_lifetime
448
+ )
449
+ self ._pool_timeout = pool_timeout
428
450
429
451
async def _async__init__ (self ):
430
452
if self ._initialized :
@@ -578,7 +600,7 @@ async def execute(
578
600
self ,
579
601
query : str ,
580
602
* args ,
581
- timeout : Optional [float ]= None ,
603
+ timeout : Optional [float ] = None ,
582
604
) -> str :
583
605
"""Execute an SQL command (or commands).
584
606
@@ -596,7 +618,7 @@ async def executemany(
596
618
command : str ,
597
619
args ,
598
620
* ,
599
- timeout : Optional [float ]= None ,
621
+ timeout : Optional [float ] = None ,
600
622
):
601
623
"""Execute an SQL *command* for each sequence of arguments in *args*.
602
624
@@ -853,6 +875,7 @@ def acquire(self, *, timeout=None):
853
875
"""Acquire a database connection from the pool.
854
876
855
877
:param float timeout: A timeout for acquiring a Connection.
878
+ If not specified, defaults to the pool's *pool_timeout*.
856
879
:return: An instance of :class:`~asyncpg.connection.Connection`.
857
880
858
881
Can be used in an ``await`` expression or with an ``async with`` block.
@@ -892,11 +915,16 @@ async def _acquire_impl():
892
915
raise exceptions .InterfaceError ('pool is closing' )
893
916
self ._check_init ()
894
917
895
- if timeout is None :
918
+ # Use pool_timeout as fallback if no timeout specified
919
+ effective_timeout = timeout or self ._pool_timeout
920
+
921
+ if effective_timeout is None :
896
922
return await _acquire_impl ()
897
923
else :
898
924
return await compat .wait_for (
899
- _acquire_impl (), timeout = timeout )
925
+ _acquire_impl (),
926
+ timeout = effective_timeout
927
+ )
900
928
901
929
async def release (self , connection , * , timeout = None ):
902
930
"""Release a database connection back to the pool.
@@ -906,7 +934,8 @@ async def release(self, connection, *, timeout=None):
906
934
:param float timeout:
907
935
A timeout for releasing the connection. If not specified, defaults
908
936
to the timeout provided in the corresponding call to the
909
- :meth:`Pool.acquire() <asyncpg.pool.Pool.acquire>` method.
937
+ :meth:`Pool.acquire() <asyncpg.pool.Pool.acquire>` method, or
938
+ to the pool's *pool_timeout* if no acquire timeout was set.
910
939
911
940
.. versionchanged:: 0.14.0
912
941
Added the *timeout* parameter.
@@ -929,7 +958,7 @@ async def release(self, connection, *, timeout=None):
929
958
930
959
ch = connection ._holder
931
960
if timeout is None :
932
- timeout = ch ._timeout
961
+ timeout = ch ._timeout or self . _pool_timeout
933
962
934
963
# Use asyncio.shield() to guarantee that task cancellation
935
964
# does not prevent the connection from being returned to the
@@ -1065,26 +1094,32 @@ async def __aexit__(
1065
1094
self .done = True
1066
1095
con = self .connection
1067
1096
self .connection = None
1068
- await self .pool .release (con )
1097
+ # Use the acquire timeout if set, otherwise fall back to pool_timeout
1098
+ release_timeout = self .timeout or self .pool ._pool_timeout
1099
+ await self .pool .release (con , timeout = release_timeout )
1069
1100
1070
1101
def __await__ (self ):
1071
1102
self .done = True
1072
1103
return self .pool ._acquire (self .timeout ).__await__ ()
1073
1104
1074
1105
1075
- def create_pool (dsn = None , * ,
1076
- min_size = 10 ,
1077
- max_size = 10 ,
1078
- max_queries = 50000 ,
1079
- max_inactive_connection_lifetime = 300.0 ,
1080
- connect = None ,
1081
- setup = None ,
1082
- init = None ,
1083
- reset = None ,
1084
- loop = None ,
1085
- connection_class = connection .Connection ,
1086
- record_class = protocol .Record ,
1087
- ** connect_kwargs ):
1106
+ def create_pool (
1107
+ dsn = None ,
1108
+ * ,
1109
+ min_size = 10 ,
1110
+ max_size = 10 ,
1111
+ max_queries = 50000 ,
1112
+ max_inactive_connection_lifetime = 300.0 ,
1113
+ pool_timeout = None ,
1114
+ connect = None ,
1115
+ setup = None ,
1116
+ init = None ,
1117
+ reset = None ,
1118
+ loop = None ,
1119
+ connection_class = connection .Connection ,
1120
+ record_class = protocol .Record ,
1121
+ ** connect_kwargs ,
1122
+ ):
1088
1123
r"""Create a connection pool.
1089
1124
1090
1125
Can be used either with an ``async with`` block:
@@ -1161,6 +1196,11 @@ def create_pool(dsn=None, *,
1161
1196
Number of seconds after which inactive connections in the
1162
1197
pool will be closed. Pass ``0`` to disable this mechanism.
1163
1198
1199
+ :param float pool_timeout:
1200
+ Default timeout for pool operations (connection acquire and release).
1201
+ If not specified, pool operations may hang indefinitely. Individual
1202
+ operations can override this with their own timeout parameters.
1203
+
1164
1204
:param coroutine connect:
1165
1205
A coroutine that is called instead of
1166
1206
:func:`~asyncpg.connection.connect` whenever the pool needs to make a
@@ -1238,6 +1278,7 @@ def create_pool(dsn=None, *,
1238
1278
min_size = min_size ,
1239
1279
max_size = max_size ,
1240
1280
max_queries = max_queries ,
1281
+ pool_timeout = pool_timeout ,
1241
1282
loop = loop ,
1242
1283
connect = connect ,
1243
1284
setup = setup ,
0 commit comments