-
-
Notifications
You must be signed in to change notification settings - Fork 761
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
--timeout-graceful-shutdown
parameter (#1950)
Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
- Loading branch information
Showing
8 changed files
with
154 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import asyncio | ||
import signal | ||
from asyncio import Event | ||
|
||
import httpx | ||
import pytest | ||
|
||
from tests.utils import run_server | ||
from uvicorn import Server | ||
from uvicorn.config import Config | ||
|
||
|
||
@pytest.mark.anyio | ||
async def test_sigint_finish_req(unused_tcp_port: int): | ||
""" | ||
1. Request is sent | ||
2. Sigint is sent to uvicorn | ||
3. Shutdown sequence start | ||
4. Request is finished before timeout_graceful_shutdown=1 | ||
Result: Request should go through, even though the server was cancelled. | ||
""" | ||
|
||
server_event = Event() | ||
|
||
async def wait_app(scope, receive, send): | ||
await send({"type": "http.response.start", "status": 200, "headers": []}) | ||
await send({"type": "http.response.body", "body": b"start", "more_body": True}) | ||
await server_event.wait() | ||
await send({"type": "http.response.body", "body": b"end", "more_body": False}) | ||
|
||
config = Config( | ||
app=wait_app, reload=False, port=unused_tcp_port, timeout_graceful_shutdown=1 | ||
) | ||
server: Server | ||
async with run_server(config) as server: | ||
async with httpx.AsyncClient() as client: | ||
Event() | ||
req = asyncio.create_task(client.get(f"http://127.0.0.1:{unused_tcp_port}")) | ||
await asyncio.sleep(0.1) # ensure next tick | ||
server.handle_exit(sig=signal.SIGINT, frame=None) # exit | ||
server_event.set() # continue request | ||
# ensure httpx has processed the response and result is complete | ||
await req | ||
assert req.result().status_code == 200 | ||
|
||
|
||
@pytest.mark.anyio | ||
async def test_sigint_abort_req(unused_tcp_port: int, caplog): | ||
""" | ||
1. Request is sent | ||
2. Sigint is sent to uvicorn | ||
3. Shutdown sequence start | ||
4. Request is _NOT_ finished before timeout_graceful_shutdown=1 | ||
Result: Request is cancelled mid-execution, and httpx will raise a `RemoteProtocolError` | ||
""" | ||
|
||
async def forever_app(scope, receive, send): | ||
server_event = Event() | ||
await send({"type": "http.response.start", "status": 200, "headers": []}) | ||
await send({"type": "http.response.body", "body": b"start", "more_body": True}) | ||
await server_event.wait() # we never continue this one, so this request will time out | ||
await send({"type": "http.response.body", "body": b"end", "more_body": False}) | ||
|
||
config = Config( | ||
app=forever_app, reload=False, port=unused_tcp_port, timeout_graceful_shutdown=1 | ||
) | ||
server: Server | ||
async with run_server(config) as server: | ||
async with httpx.AsyncClient() as client: | ||
Event() | ||
req = asyncio.create_task(client.get(f"http://127.0.0.1:{unused_tcp_port}")) | ||
await asyncio.sleep(0.1) # next tick | ||
# trigger exit, this request should time out in ~1 sec | ||
server.handle_exit(sig=signal.SIGINT, frame=None) | ||
with pytest.raises(httpx.RemoteProtocolError): | ||
await req | ||
|
||
# req.result() | ||
assert ( | ||
"Cancel 1 running task(s), timeout graceful shutdown exceeded" | ||
in caplog.messages | ||
) | ||
|
||
|
||
@pytest.mark.anyio | ||
async def test_sigint_deny_request_after_triggered(unused_tcp_port: int, caplog): | ||
""" | ||
1. Server is started | ||
2. Shutdown sequence start | ||
3. Request is sent, but not accepted | ||
Result: Request should fail, and not be able to be sent, since server is no longer accepting connections | ||
""" | ||
|
||
async def app(scope, receive, send): | ||
await send({"type": "http.response.start", "status": 200, "headers": []}) | ||
await asyncio.sleep(1) | ||
|
||
config = Config( | ||
app=app, reload=False, port=unused_tcp_port, timeout_graceful_shutdown=1 | ||
) | ||
server: Server | ||
async with run_server(config) as server: | ||
# exit and ensure we do not accept more requests | ||
server.handle_exit(sig=signal.SIGINT, frame=None) | ||
await asyncio.sleep(0.1) # next tick | ||
async with httpx.AsyncClient() as client: | ||
with pytest.raises(httpx.ConnectError): | ||
await client.get(f"http://127.0.0.1:{unused_tcp_port}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters