uvicorn 0.28.1__tar.gz → 0.29.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {uvicorn-0.28.1 → uvicorn-0.29.0}/PKG-INFO +1 -1
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/__init__.py +1 -1
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/server.py +25 -14
- {uvicorn-0.28.1 → uvicorn-0.29.0}/.gitignore +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/LICENSE.md +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/README.md +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/pyproject.toml +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/__main__.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/_subprocess.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/_types.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/config.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/importer.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/lifespan/__init__.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/lifespan/off.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/lifespan/on.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/logging.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/loops/__init__.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/loops/asyncio.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/loops/auto.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/loops/uvloop.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/main.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/middleware/__init__.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/middleware/asgi2.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/middleware/message_logger.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/middleware/proxy_headers.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/middleware/wsgi.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/protocols/__init__.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/protocols/http/__init__.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/protocols/http/auto.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/protocols/http/flow_control.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/protocols/http/h11_impl.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/protocols/http/httptools_impl.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/protocols/utils.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/protocols/websockets/__init__.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/protocols/websockets/auto.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/protocols/websockets/websockets_impl.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/protocols/websockets/wsproto_impl.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/py.typed +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/supervisors/__init__.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/supervisors/basereload.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/supervisors/multiprocess.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/supervisors/statreload.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/supervisors/watchfilesreload.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/supervisors/watchgodreload.py +0 -0
- {uvicorn-0.28.1 → uvicorn-0.29.0}/uvicorn/workers.py +0 -0
@@ -1,6 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import asyncio
|
4
|
+
import contextlib
|
4
5
|
import logging
|
5
6
|
import os
|
6
7
|
import platform
|
@@ -11,7 +12,7 @@ import threading
|
|
11
12
|
import time
|
12
13
|
from email.utils import formatdate
|
13
14
|
from types import FrameType
|
14
|
-
from typing import TYPE_CHECKING, Sequence, Union
|
15
|
+
from typing import TYPE_CHECKING, Generator, Sequence, Union
|
15
16
|
|
16
17
|
import click
|
17
18
|
|
@@ -57,11 +58,17 @@ class Server:
|
|
57
58
|
self.force_exit = False
|
58
59
|
self.last_notified = 0.0
|
59
60
|
|
61
|
+
self._captured_signals: list[int] = []
|
62
|
+
|
60
63
|
def run(self, sockets: list[socket.socket] | None = None) -> None:
|
61
64
|
self.config.setup_event_loop()
|
62
65
|
return asyncio.run(self.serve(sockets=sockets))
|
63
66
|
|
64
67
|
async def serve(self, sockets: list[socket.socket] | None = None) -> None:
|
68
|
+
with self.capture_signals():
|
69
|
+
await self._serve(sockets)
|
70
|
+
|
71
|
+
async def _serve(self, sockets: list[socket.socket] | None = None) -> None:
|
65
72
|
process_id = os.getpid()
|
66
73
|
|
67
74
|
config = self.config
|
@@ -70,8 +77,6 @@ class Server:
|
|
70
77
|
|
71
78
|
self.lifespan = config.lifespan_class(config)
|
72
79
|
|
73
|
-
self.install_signal_handlers()
|
74
|
-
|
75
80
|
message = "Started server process [%d]"
|
76
81
|
color_message = "Started server process [" + click.style("%d", fg="cyan") + "]"
|
77
82
|
logger.info(message, process_id, extra={"color_message": color_message})
|
@@ -302,22 +307,28 @@ class Server:
|
|
302
307
|
for server in self.servers:
|
303
308
|
await server.wait_closed()
|
304
309
|
|
305
|
-
|
310
|
+
@contextlib.contextmanager
|
311
|
+
def capture_signals(self) -> Generator[None, None, None]:
|
312
|
+
# Signals can only be listened to from the main thread.
|
306
313
|
if threading.current_thread() is not threading.main_thread():
|
307
|
-
|
314
|
+
yield
|
308
315
|
return
|
309
|
-
|
310
|
-
|
311
|
-
|
316
|
+
# always use signal.signal, even if loop.add_signal_handler is available
|
317
|
+
# this allows to restore previous signal handlers later on
|
318
|
+
original_handlers = {sig: signal.signal(sig, self.handle_exit) for sig in HANDLED_SIGNALS}
|
312
319
|
try:
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
320
|
+
yield
|
321
|
+
finally:
|
322
|
+
for sig, handler in original_handlers.items():
|
323
|
+
signal.signal(sig, handler)
|
324
|
+
# If we did gracefully shut down due to a signal, try to
|
325
|
+
# trigger the expected behaviour now; multiple signals would be
|
326
|
+
# done LIFO, see https://stackoverflow.com/questions/48434964
|
327
|
+
for captured_signal in reversed(self._captured_signals):
|
328
|
+
signal.raise_signal(captured_signal)
|
319
329
|
|
320
330
|
def handle_exit(self, sig: int, frame: FrameType | None) -> None:
|
331
|
+
self._captured_signals.append(sig)
|
321
332
|
if self.should_exit and sig == signal.SIGINT:
|
322
333
|
self.force_exit = True
|
323
334
|
else:
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|