File tree 4 files changed +41
-18
lines changed
4 files changed +41
-18
lines changed Original file line number Diff line number Diff line change @@ -90,3 +90,19 @@ async def wait_closed(stream):
90
90
# On Windows wait_closed() sometimes propagates
91
91
# ConnectionResetError which is totally unnecessary.
92
92
pass
93
+
94
+
95
+ # Workaround for https://bugs.python.org/issue37658
96
+ async def wait_for (fut , timeout ):
97
+ if timeout is None :
98
+ return await fut
99
+
100
+ fut = asyncio .ensure_future (fut )
101
+
102
+ try :
103
+ return await asyncio .wait_for (fut , timeout )
104
+ except asyncio .CancelledError :
105
+ if fut .done ():
106
+ return fut .result ()
107
+ else :
108
+ raise
Original file line number Diff line number Diff line change @@ -636,18 +636,13 @@ async def _connect_addr(
636
636
637
637
connector = asyncio .ensure_future (connector )
638
638
before = time .monotonic ()
639
- try :
640
- tr , pr = await asyncio .wait_for (
641
- connector , timeout = timeout )
642
- except asyncio .CancelledError :
643
- connector .add_done_callback (_close_leaked_connection )
644
- raise
639
+ tr , pr = await compat .wait_for (connector , timeout = timeout )
645
640
timeout -= time .monotonic () - before
646
641
647
642
try :
648
643
if timeout <= 0 :
649
644
raise asyncio .TimeoutError
650
- await asyncio .wait_for (connected , timeout = timeout )
645
+ await compat .wait_for (connected , timeout = timeout )
651
646
except (Exception , asyncio .CancelledError ):
652
647
tr .close ()
653
648
raise
@@ -745,12 +740,3 @@ def _create_future(loop):
745
740
return asyncio .Future (loop = loop )
746
741
else :
747
742
return create_future ()
748
-
749
-
750
- def _close_leaked_connection (fut ):
751
- try :
752
- tr , pr = fut .result ()
753
- if tr :
754
- tr .close ()
755
- except asyncio .CancelledError :
756
- pass # hide the exception
Original file line number Diff line number Diff line change 12
12
import time
13
13
import warnings
14
14
15
+ from . import compat
15
16
from . import connection
16
17
from . import connect_utils
17
18
from . import exceptions
@@ -198,7 +199,7 @@ async def release(self, timeout):
198
199
# If the connection is in cancellation state,
199
200
# wait for the cancellation
200
201
started = time .monotonic ()
201
- await asyncio .wait_for (
202
+ await compat .wait_for (
202
203
self ._con ._protocol ._wait_for_cancellation (),
203
204
budget )
204
205
if budget is not None :
@@ -623,7 +624,7 @@ async def _acquire_impl():
623
624
if timeout is None :
624
625
return await _acquire_impl ()
625
626
else :
626
- return await asyncio .wait_for (
627
+ return await compat .wait_for (
627
628
_acquire_impl (), timeout = timeout )
628
629
629
630
async def release (self , connection , * , timeout = None ):
Original file line number Diff line number Diff line change @@ -379,6 +379,26 @@ async def worker():
379
379
self .cluster .trust_local_connections ()
380
380
self .cluster .reload ()
381
381
382
+ async def test_pool_handles_task_cancel_in_acquire_with_timeout (self ):
383
+ # See https://github.com/MagicStack/asyncpg/issues/547
384
+ pool = await self .create_pool (database = 'postgres' ,
385
+ min_size = 1 , max_size = 1 )
386
+
387
+ async def worker ():
388
+ async with pool .acquire (timeout = 100 ):
389
+ pass
390
+
391
+ # Schedule task
392
+ task = self .loop .create_task (worker ())
393
+ # Yield to task, but cancel almost immediately
394
+ await asyncio .sleep (0.00000000001 )
395
+ # Cancel the worker.
396
+ task .cancel ()
397
+ # Wait to make sure the cleanup has completed.
398
+ await asyncio .sleep (0.4 )
399
+ # Check that the connection has been returned to the pool.
400
+ self .assertEqual (pool ._queue .qsize (), 1 )
401
+
382
402
async def test_pool_handles_task_cancel_in_release (self ):
383
403
# Use SlowResetConnectionPool to simulate
384
404
# the Task.cancel() and __aexit__ race.
You can’t perform that action at this time.
0 commit comments