Skip to content

Commit 719c46d

Browse files
authored
Modernize loop handling in asgiref.server (#503)
1 parent a0e2159 commit 719c46d

File tree

3 files changed

+43
-34
lines changed

3 files changed

+43
-34
lines changed

asgiref/server.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,28 @@ def run(self):
5757
Runs the asyncio event loop with our handler loop.
5858
"""
5959
event_loop = asyncio.get_event_loop()
60-
asyncio.ensure_future(self.application_checker())
6160
try:
62-
event_loop.run_until_complete(self.handle())
61+
event_loop.run_until_complete(self.arun())
6362
except KeyboardInterrupt:
6463
logger.info("Exiting due to Ctrl-C/interrupt")
6564

65+
async def arun(self):
66+
"""
67+
Runs the asyncio event loop with our handler loop.
68+
"""
69+
70+
class Done(Exception):
71+
pass
72+
73+
async def handle():
74+
await self.handle()
75+
raise Done
76+
77+
try:
78+
await asyncio.gather(self.application_checker(), handle())
79+
except Done:
80+
pass
81+
6682
async def handle(self):
6783
raise NotImplementedError("You must implement handle()")
6884

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ tests =
4444
[tool:pytest]
4545
testpaths = tests
4646
asyncio_mode = strict
47+
asyncio_default_fixture_loop_scope=function
4748

4849
[flake8]
4950
exclude = venv/*,tox/*,specs/*

tests/test_server.py

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import asyncio
22
import socket as sock
3-
from functools import partial
43

54
import pytest
5+
import pytest_asyncio
66

77
from asgiref.server import StatelessServer
88

@@ -74,8 +74,8 @@ def close(self):
7474
self._sock.close()
7575

7676

77-
@pytest.fixture(scope="function")
78-
def server():
77+
@pytest_asyncio.fixture(scope="function")
78+
async def server():
7979
async def app(scope, receive, send):
8080
while True:
8181
msg = await receive()
@@ -92,25 +92,12 @@ async def check_client_msg(client, expected_address, expected_msg):
9292
assert server_addr == expected_address
9393

9494

95-
async def server_auto_close(fut, timeout):
96-
"""Server run based on run_until_complete. It will block forever with handle
97-
function because it is a while True loop without break. Use this method to close
98-
server automatically."""
99-
loop = asyncio.get_running_loop()
100-
task = asyncio.ensure_future(fut, loop=loop)
101-
await asyncio.sleep(timeout)
102-
task.cancel()
103-
104-
105-
def test_stateless_server(server):
95+
@pytest.mark.asyncio
96+
async def test_stateless_server(server):
10697
"""StatelessServer can be instantiated with an ASGI 3 application."""
10798
"""Create a UDP Server can register instance based on name from message of client.
10899
Clients can communicate to other client by name through server"""
109100

110-
loop = asyncio.new_event_loop()
111-
asyncio.set_event_loop(loop)
112-
server.handle = partial(server_auto_close, fut=server.handle(), timeout=1.0)
113-
114101
client1 = Client(name="client1")
115102
client2 = Client(name="client2")
116103

@@ -124,30 +111,35 @@ async def check_client2_behavior():
124111
await check_client_msg(client2, server.address, b"Welcome")
125112
await check_client_msg(client2, server.address, b"Hello")
126113

127-
task1 = loop.create_task(check_client1_behavior())
128-
task2 = loop.create_task(check_client2_behavior())
114+
class Done(Exception):
115+
pass
129116

130-
server.run()
117+
async def do_test():
118+
await asyncio.gather(check_client1_behavior(), check_client2_behavior())
119+
raise Done
131120

132-
assert task1.done()
133-
assert task2.done()
121+
try:
122+
await asyncio.gather(server.arun(), do_test())
123+
except Done:
124+
pass
134125

135126

136-
def test_server_delete_instance(server):
127+
@pytest.mark.asyncio
128+
async def test_server_delete_instance(server):
137129
"""The max_applications of Server is 10. After 20 times register, application number should be 10."""
138-
loop = asyncio.new_event_loop()
139-
asyncio.set_event_loop(loop)
140-
server.handle = partial(server_auto_close, fut=server.handle(), timeout=1.0)
141-
142130
client1 = Client(name="client1")
143131

132+
class Done(Exception):
133+
pass
134+
144135
async def client1_multiple_register():
145136
for i in range(20):
146137
await client1.register(server.address, name=f"client{i}")
147138
print(f"client{i}")
148139
await check_client_msg(client1, server.address, b"Welcome")
140+
raise Done
149141

150-
task = loop.create_task(client1_multiple_register())
151-
server.run()
152-
153-
assert task.done()
142+
try:
143+
await asyncio.gather(client1_multiple_register(), server.arun())
144+
except Done:
145+
pass

0 commit comments

Comments
 (0)