Merge pull request #1361 from yunstanford/cancel-request-when-connection-lost

Cancel request when connection lost
This commit is contained in:
Stephen Sadowski 2018-10-12 07:25:10 -05:00 committed by GitHub
commit 41759248e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 77 additions and 0 deletions

View File

@ -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:

View 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