| 54 | |
| 55 | |
| 56 | class Server: |
| 57 | def __init__(self, config: Config) -> None: |
| 58 | self.config = config |
| 59 | self.server_state = ServerState() |
| 60 | |
| 61 | self.started = False |
| 62 | self.should_exit = False |
| 63 | self.force_exit = False |
| 64 | self.last_notified = 0.0 |
| 65 | |
| 66 | self._captured_signals: list[int] = [] |
| 67 | |
| 68 | @functools.cached_property |
| 69 | def limit_max_requests(self) -> int | None: |
| 70 | if self.config.limit_max_requests is None: |
| 71 | return None |
| 72 | return self.config.limit_max_requests + random.randint(0, self.config.limit_max_requests_jitter) |
| 73 | |
| 74 | def run(self, sockets: list[socket.socket] | None = None) -> None: |
| 75 | return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory()) |
| 76 | |
| 77 | async def serve(self, sockets: list[socket.socket] | None = None) -> None: |
| 78 | with self.capture_signals(): |
| 79 | await self._serve(sockets) |
| 80 | |
| 81 | async def _serve(self, sockets: list[socket.socket] | None = None) -> None: |
| 82 | process_id = os.getpid() |
| 83 | |
| 84 | config = self.config |
| 85 | if not config.loaded: |
| 86 | config.load() |
| 87 | |
| 88 | self.lifespan = config.lifespan_class(config) |
| 89 | |
| 90 | message = class="st">"Started server process [%d]" |
| 91 | color_message = class="st">"Started server process [" + click.style(class="st">"%d", fg=class="st">"cyan") + class="st">"]" |
| 92 | logger.info(message, process_id, extra={class="st">"color_message": color_message}) |
| 93 | |
| 94 | await self.startup(sockets=sockets) |
| 95 | if not self.should_exit: |
| 96 | await self.main_loop() |
| 97 | if self.started: |
| 98 | await self.shutdown(sockets=sockets) |
| 99 | |
| 100 | message = class="st">"Finished server process [%d]" |
| 101 | color_message = class="st">"Finished server process [" + click.style(class="st">"%d", fg=class="st">"cyan") + class="st">"]" |
| 102 | logger.info(message, process_id, extra={class="st">"color_message": color_message}) |
| 103 | |
| 104 | async def startup(self, sockets: list[socket.socket] | None = None) -> None: |
| 105 | await self.lifespan.startup() |
| 106 | if self.lifespan.should_exit: |
| 107 | self.should_exit = True |
| 108 | return |
| 109 | |
| 110 | config = self.config |
| 111 | |
| 112 | def create_protocol( |
| 113 | _loop: asyncio.AbstractEventLoop | None = None, |
no outgoing calls