Merge pull request #1361 from yunstanford/cancel-request-when-connection-lost
Cancel request when connection lost
This commit is contained in:
commit
41759248e2
|
@ -120,6 +120,10 @@ class HttpProtocol(asyncio.Protocol):
|
||||||
|
|
||||||
def connection_lost(self, exc):
|
def connection_lost(self, exc):
|
||||||
self.connections.discard(self)
|
self.connections.discard(self)
|
||||||
|
if self._request_handler_task:
|
||||||
|
self._request_handler_task.cancel()
|
||||||
|
if self._request_stream_task:
|
||||||
|
self._request_stream_task.cancel()
|
||||||
if self._request_timeout_handler:
|
if self._request_timeout_handler:
|
||||||
self._request_timeout_handler.cancel()
|
self._request_timeout_handler.cancel()
|
||||||
if self._response_timeout_handler:
|
if self._response_timeout_handler:
|
||||||
|
|
73
tests/test_request_cancel.py
Normal file
73
tests/test_request_cancel.py
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
import pytest
|
||||||
|
import asyncio
|
||||||
|
import contextlib
|
||||||
|
|
||||||
|
from sanic.response import text, stream
|
||||||
|
|
||||||
|
|
||||||
|
async def test_request_cancel_when_connection_lost(loop, app, test_client):
|
||||||
|
app.still_serving_cancelled_request = False
|
||||||
|
|
||||||
|
@app.get('/')
|
||||||
|
async def handler(request):
|
||||||
|
await asyncio.sleep(1.0)
|
||||||
|
# at this point client is already disconnected
|
||||||
|
app.still_serving_cancelled_request = True
|
||||||
|
return text('OK')
|
||||||
|
|
||||||
|
test_cli = await test_client(app)
|
||||||
|
|
||||||
|
# schedule client call
|
||||||
|
task = loop.create_task(test_cli.get('/'))
|
||||||
|
loop.call_later(0.01, task)
|
||||||
|
await asyncio.sleep(0.5)
|
||||||
|
|
||||||
|
# cancelling request and closing connection after 0.5 sec
|
||||||
|
task.cancel()
|
||||||
|
|
||||||
|
with contextlib.suppress(asyncio.CancelledError):
|
||||||
|
await task
|
||||||
|
|
||||||
|
# Wait for server and check if it's still serving the cancelled request
|
||||||
|
await asyncio.sleep(1.0)
|
||||||
|
|
||||||
|
assert app.still_serving_cancelled_request is False
|
||||||
|
|
||||||
|
|
||||||
|
async def test_stream_request_cancel_when_connection_lost(loop, app, test_client):
|
||||||
|
app.still_serving_cancelled_request = False
|
||||||
|
|
||||||
|
@app.post('/post/<id>', stream=True)
|
||||||
|
async def post(request, id):
|
||||||
|
assert isinstance(request.stream, asyncio.Queue)
|
||||||
|
|
||||||
|
async def streaming(response):
|
||||||
|
while True:
|
||||||
|
body = await request.stream.get()
|
||||||
|
if body is None:
|
||||||
|
break
|
||||||
|
await response.write(body.decode('utf-8'))
|
||||||
|
|
||||||
|
await asyncio.sleep(1.0)
|
||||||
|
# at this point client is already disconnected
|
||||||
|
app.still_serving_cancelled_request = True
|
||||||
|
|
||||||
|
return stream(streaming)
|
||||||
|
|
||||||
|
test_cli = await test_client(app)
|
||||||
|
|
||||||
|
# schedule client call
|
||||||
|
task = loop.create_task(test_cli.post('/post/1'))
|
||||||
|
loop.call_later(0.01, task)
|
||||||
|
await asyncio.sleep(0.5)
|
||||||
|
|
||||||
|
# cancelling request and closing connection after 0.5 sec
|
||||||
|
task.cancel()
|
||||||
|
|
||||||
|
with contextlib.suppress(asyncio.CancelledError):
|
||||||
|
await task
|
||||||
|
|
||||||
|
# Wait for server and check if it's still serving the cancelled request
|
||||||
|
await asyncio.sleep(1.0)
|
||||||
|
|
||||||
|
assert app.still_serving_cancelled_request is False
|
Loading…
Reference in New Issue
Block a user