mirror of
https://gitlab.com/MoonTestUse1/AdministrationItDepartmens.git
synced 2025-08-14 00:25:46 +02:00
Проверка 09.02.2025
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import contextlib
|
||||
import logging
|
||||
import os
|
||||
import platform
|
||||
@@ -9,9 +10,10 @@ import socket
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
from collections.abc import Generator, Sequence
|
||||
from email.utils import formatdate
|
||||
from types import FrameType
|
||||
from typing import TYPE_CHECKING, Sequence, Union
|
||||
from typing import TYPE_CHECKING, Union
|
||||
|
||||
import click
|
||||
|
||||
@@ -57,11 +59,17 @@ class Server:
|
||||
self.force_exit = False
|
||||
self.last_notified = 0.0
|
||||
|
||||
self._captured_signals: list[int] = []
|
||||
|
||||
def run(self, sockets: list[socket.socket] | None = None) -> None:
|
||||
self.config.setup_event_loop()
|
||||
return asyncio.run(self.serve(sockets=sockets))
|
||||
|
||||
async def serve(self, sockets: list[socket.socket] | None = None) -> None:
|
||||
with self.capture_signals():
|
||||
await self._serve(sockets)
|
||||
|
||||
async def _serve(self, sockets: list[socket.socket] | None = None) -> None:
|
||||
process_id = os.getpid()
|
||||
|
||||
config = self.config
|
||||
@@ -70,8 +78,6 @@ class Server:
|
||||
|
||||
self.lifespan = config.lifespan_class(config)
|
||||
|
||||
self.install_signal_handlers()
|
||||
|
||||
message = "Started server process [%d]"
|
||||
color_message = "Started server process [" + click.style("%d", fg="cyan") + "]"
|
||||
logger.info(message, process_id, extra={"color_message": color_message})
|
||||
@@ -107,7 +113,7 @@ class Server:
|
||||
loop = asyncio.get_running_loop()
|
||||
|
||||
listeners: Sequence[socket.SocketType]
|
||||
if sockets is not None:
|
||||
if sockets is not None: # pragma: full coverage
|
||||
# Explicitly passed a list of open sockets.
|
||||
# We use this when the server is run from a Gunicorn worker.
|
||||
|
||||
@@ -126,18 +132,14 @@ class Server:
|
||||
is_windows = platform.system() == "Windows"
|
||||
if config.workers > 1 and is_windows: # pragma: py-not-win32
|
||||
sock = _share_socket(sock) # type: ignore[assignment]
|
||||
server = await loop.create_server(
|
||||
create_protocol, sock=sock, ssl=config.ssl, backlog=config.backlog
|
||||
)
|
||||
server = await loop.create_server(create_protocol, sock=sock, ssl=config.ssl, backlog=config.backlog)
|
||||
self.servers.append(server)
|
||||
listeners = sockets
|
||||
|
||||
elif config.fd is not None: # pragma: py-win32
|
||||
# Use an existing socket, from a file descriptor.
|
||||
sock = socket.fromfd(config.fd, socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
server = await loop.create_server(
|
||||
create_protocol, sock=sock, ssl=config.ssl, backlog=config.backlog
|
||||
)
|
||||
server = await loop.create_server(create_protocol, sock=sock, ssl=config.ssl, backlog=config.backlog)
|
||||
assert server.sockets is not None # mypy
|
||||
listeners = server.sockets
|
||||
self.servers = [server]
|
||||
@@ -146,7 +148,7 @@ class Server:
|
||||
# Create a socket using UNIX domain socket.
|
||||
uds_perms = 0o666
|
||||
if os.path.exists(config.uds):
|
||||
uds_perms = os.stat(config.uds).st_mode
|
||||
uds_perms = os.stat(config.uds).st_mode # pragma: full coverage
|
||||
server = await loop.create_unix_server(
|
||||
create_protocol, path=config.uds, ssl=config.ssl, backlog=config.backlog
|
||||
)
|
||||
@@ -179,7 +181,7 @@ class Server:
|
||||
else:
|
||||
# We're most likely running multiple workers, so a message has already been
|
||||
# logged by `config.bind_socket()`.
|
||||
pass
|
||||
pass # pragma: full coverage
|
||||
|
||||
self.started = True
|
||||
|
||||
@@ -194,9 +196,7 @@ class Server:
|
||||
)
|
||||
|
||||
elif config.uds is not None: # pragma: py-win32
|
||||
logger.info(
|
||||
"Uvicorn running on unix socket %s (Press CTRL+C to quit)", config.uds
|
||||
)
|
||||
logger.info("Uvicorn running on unix socket %s (Press CTRL+C to quit)", config.uds)
|
||||
|
||||
else:
|
||||
addr_format = "%s://%s:%d"
|
||||
@@ -211,11 +211,7 @@ class Server:
|
||||
|
||||
protocol_name = "https" if config.ssl else "http"
|
||||
message = f"Uvicorn running on {addr_format} (Press CTRL+C to quit)"
|
||||
color_message = (
|
||||
"Uvicorn running on "
|
||||
+ click.style(addr_format, bold=True)
|
||||
+ " (Press CTRL+C to quit)"
|
||||
)
|
||||
color_message = "Uvicorn running on " + click.style(addr_format, bold=True) + " (Press CTRL+C to quit)"
|
||||
logger.info(
|
||||
message,
|
||||
protocol_name,
|
||||
@@ -244,21 +240,23 @@ class Server:
|
||||
else:
|
||||
date_header = []
|
||||
|
||||
self.server_state.default_headers = (
|
||||
date_header + self.config.encoded_headers
|
||||
)
|
||||
self.server_state.default_headers = date_header + self.config.encoded_headers
|
||||
|
||||
# Callback to `callback_notify` once every `timeout_notify` seconds.
|
||||
if self.config.callback_notify is not None:
|
||||
if current_time - self.last_notified > self.config.timeout_notify:
|
||||
if current_time - self.last_notified > self.config.timeout_notify: # pragma: full coverage
|
||||
self.last_notified = current_time
|
||||
await self.config.callback_notify()
|
||||
|
||||
# Determine if we should exit.
|
||||
if self.should_exit:
|
||||
return True
|
||||
if self.config.limit_max_requests is not None:
|
||||
return self.server_state.total_requests >= self.config.limit_max_requests
|
||||
|
||||
max_requests = self.config.limit_max_requests
|
||||
if max_requests is not None and self.server_state.total_requests >= max_requests:
|
||||
logger.warning(f"Maximum request limit of {max_requests} exceeded. Terminating process.")
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
async def shutdown(self, sockets: list[socket.socket] | None = None) -> None:
|
||||
@@ -268,7 +266,7 @@ class Server:
|
||||
for server in self.servers:
|
||||
server.close()
|
||||
for sock in sockets or []:
|
||||
sock.close()
|
||||
sock.close() # pragma: full coverage
|
||||
|
||||
# Request shutdown on all existing connections.
|
||||
for connection in list(self.server_state.connections):
|
||||
@@ -287,10 +285,7 @@ class Server:
|
||||
len(self.server_state.tasks),
|
||||
)
|
||||
for t in self.server_state.tasks:
|
||||
if sys.version_info < (3, 9): # pragma: py-gte-39
|
||||
t.cancel()
|
||||
else: # pragma: py-lt-39
|
||||
t.cancel(msg="Task cancelled, timeout graceful shutdown exceeded")
|
||||
t.cancel(msg="Task cancelled, timeout graceful shutdown exceeded")
|
||||
|
||||
# Send the lifespan shutdown event, and wait for application shutdown.
|
||||
if not self.force_exit:
|
||||
@@ -314,23 +309,29 @@ class Server:
|
||||
for server in self.servers:
|
||||
await server.wait_closed()
|
||||
|
||||
def install_signal_handlers(self) -> None:
|
||||
@contextlib.contextmanager
|
||||
def capture_signals(self) -> Generator[None, None, None]:
|
||||
# Signals can only be listened to from the main thread.
|
||||
if threading.current_thread() is not threading.main_thread():
|
||||
# Signals can only be listened to from the main thread.
|
||||
yield
|
||||
return
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
# always use signal.signal, even if loop.add_signal_handler is available
|
||||
# this allows to restore previous signal handlers later on
|
||||
original_handlers = {sig: signal.signal(sig, self.handle_exit) for sig in HANDLED_SIGNALS}
|
||||
try:
|
||||
for sig in HANDLED_SIGNALS:
|
||||
loop.add_signal_handler(sig, self.handle_exit, sig, None)
|
||||
except NotImplementedError: # pragma: no cover
|
||||
# Windows
|
||||
for sig in HANDLED_SIGNALS:
|
||||
signal.signal(sig, self.handle_exit)
|
||||
yield
|
||||
finally:
|
||||
for sig, handler in original_handlers.items():
|
||||
signal.signal(sig, handler)
|
||||
# If we did gracefully shut down due to a signal, try to
|
||||
# trigger the expected behaviour now; multiple signals would be
|
||||
# done LIFO, see https://stackoverflow.com/questions/48434964
|
||||
for captured_signal in reversed(self._captured_signals):
|
||||
signal.raise_signal(captured_signal)
|
||||
|
||||
def handle_exit(self, sig: int, frame: FrameType | None) -> None:
|
||||
self._captured_signals.append(sig)
|
||||
if self.should_exit and sig == signal.SIGINT:
|
||||
self.force_exit = True
|
||||
self.force_exit = True # pragma: full coverage
|
||||
else:
|
||||
self.should_exit = True
|
||||
|
Reference in New Issue
Block a user