Skip to content

Commit 5d09d11

Browse files
authored
GH-79033: Fix asyncio.Server.wait_closed() (#98582)
It was a no-op when used as recommended (after close()). I had to debug one test (test__sock_sendfile_native_failure) -- the cleanup sequence for the test fixture was botched. Hopefully that's not a portend of problems in user code -- this has never worked so people may well be doing this wrong. :-( Co-authored-by: kumar aditya
1 parent 8dbe08e commit 5d09d11

File tree

4 files changed

+30
-2
lines changed

4 files changed

+30
-2
lines changed

Lib/asyncio/base_events.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ async def serve_forever(self):
377377
self._serving_forever_fut = None
378378

379379
async def wait_closed(self):
380-
if self._sockets is None or self._waiters is None:
380+
if self._waiters is None or self._active_count == 0:
381381
return
382382
waiter = self._loop.create_future()
383383
self._waiters.append(waiter)

Lib/test/test_asyncio/test_base_events.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2052,11 +2052,11 @@ def prepare(self):
20522052

20532053
def cleanup():
20542054
server.close()
2055-
self.run_loop(server.wait_closed())
20562055
sock.close()
20572056
if proto.transport is not None:
20582057
proto.transport.close()
20592058
self.run_loop(proto.wait_closed())
2059+
self.run_loop(server.wait_closed())
20602060

20612061
self.addCleanup(cleanup)
20622062

Lib/test/test_asyncio/test_server.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,33 @@ async def main(srv):
120120
self.loop.run_until_complete(srv.serve_forever())
121121

122122

123+
class TestServer2(unittest.IsolatedAsyncioTestCase):
124+
125+
async def test_wait_closed(self):
126+
async def serve(*args):
127+
pass
128+
129+
srv = await asyncio.start_server(serve, socket_helper.HOSTv4, 0)
130+
131+
# active count = 0
132+
task1 = asyncio.create_task(srv.wait_closed())
133+
await asyncio.sleep(0)
134+
self.assertTrue(task1.done())
135+
136+
# active count != 0
137+
srv._attach()
138+
task2 = asyncio.create_task(srv.wait_closed())
139+
await asyncio.sleep(0)
140+
self.assertFalse(task2.done())
141+
142+
srv.close()
143+
await asyncio.sleep(0)
144+
self.assertFalse(task2.done())
145+
146+
srv._detach()
147+
await task2
148+
149+
123150
@unittest.skipUnless(hasattr(asyncio, 'ProactorEventLoop'), 'Windows only')
124151
class ProactorStartServerTests(BaseStartServer, unittest.TestCase):
125152

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix :func:`asyncio.Server.wait_closed` to actually do what the docs promise -- wait for all existing connections to complete, after closing the server.

0 commit comments

Comments
 (0)