Compare commits
	
		
			5 Commits
		
	
	
		
			smoother-p
			...
			motd-fixes
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 44bf7ba79a | ||
|   | 9e7ca10c52 | ||
|   | fe32f4eb74 | ||
|   | ebe29d3d26 | ||
|   | f651f7436f | 
							
								
								
									
										29
									
								
								README.rst
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								README.rst
									
									
									
									
									
								
							| @@ -11,7 +11,7 @@ Sanic | Build fast. Run fast. | |||||||
|     :stub-columns: 1 |     :stub-columns: 1 | ||||||
|  |  | ||||||
|     * - Build |     * - Build | ||||||
|       - | |Py310Test| |Py39Test| |Py38Test| |       - | |Py310Test| |Py39Test| |Py38Test| |Py37Test| | ||||||
|     * - Docs |     * - Docs | ||||||
|       - | |UserGuide| |Documentation| |       - | |UserGuide| |Documentation| | ||||||
|     * - Package |     * - Package | ||||||
| @@ -19,7 +19,7 @@ Sanic | Build fast. Run fast. | |||||||
|     * - Support |     * - Support | ||||||
|       - | |Forums| |Discord| |Awesome| |       - | |Forums| |Discord| |Awesome| | ||||||
|     * - Stats |     * - Stats | ||||||
|       - | |Monthly Downloads| |Weekly Downloads| |Conda downloads| |       - | |Downloads| |WkDownloads| |Conda downloads| | ||||||
|  |  | ||||||
| .. |UserGuide| image:: https://img.shields.io/badge/user%20guide-sanic-ff0068 | .. |UserGuide| image:: https://img.shields.io/badge/user%20guide-sanic-ff0068 | ||||||
|    :target: https://sanicframework.org/ |    :target: https://sanicframework.org/ | ||||||
| @@ -33,6 +33,8 @@ Sanic | Build fast. Run fast. | |||||||
|    :target: https://github.com/sanic-org/sanic/actions/workflows/pr-python39.yml |    :target: https://github.com/sanic-org/sanic/actions/workflows/pr-python39.yml | ||||||
| .. |Py38Test| image:: https://github.com/sanic-org/sanic/actions/workflows/pr-python38.yml/badge.svg?branch=main | .. |Py38Test| image:: https://github.com/sanic-org/sanic/actions/workflows/pr-python38.yml/badge.svg?branch=main | ||||||
|    :target: https://github.com/sanic-org/sanic/actions/workflows/pr-python38.yml |    :target: https://github.com/sanic-org/sanic/actions/workflows/pr-python38.yml | ||||||
|  | .. |Py37Test| image:: https://github.com/sanic-org/sanic/actions/workflows/pr-python37.yml/badge.svg?branch=main | ||||||
|  |    :target: https://github.com/sanic-org/sanic/actions/workflows/pr-python37.yml | ||||||
| .. |Documentation| image:: https://readthedocs.org/projects/sanic/badge/?version=latest | .. |Documentation| image:: https://readthedocs.org/projects/sanic/badge/?version=latest | ||||||
|    :target: http://sanic.readthedocs.io/en/latest/?badge=latest |    :target: http://sanic.readthedocs.io/en/latest/?badge=latest | ||||||
| .. |PyPI| image:: https://img.shields.io/pypi/v/sanic.svg | .. |PyPI| image:: https://img.shields.io/pypi/v/sanic.svg | ||||||
| @@ -50,23 +52,19 @@ Sanic | Build fast. Run fast. | |||||||
| .. |Awesome| image:: https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg | .. |Awesome| image:: https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg | ||||||
|     :alt: Awesome Sanic List |     :alt: Awesome Sanic List | ||||||
|     :target: https://github.com/mekicha/awesome-sanic |     :target: https://github.com/mekicha/awesome-sanic | ||||||
| .. |Monthly Downloads| image:: https://img.shields.io/pypi/dm/sanic.svg | .. |Downloads| image:: https://pepy.tech/badge/sanic/month | ||||||
|     :alt: Downloads |     :alt: Downloads | ||||||
|     :target: https://pepy.tech/project/sanic |     :target: https://pepy.tech/project/sanic | ||||||
| .. |Weekly Downloads| image:: https://img.shields.io/pypi/dw/sanic.svg | .. |WkDownloads| image:: https://pepy.tech/badge/sanic/week | ||||||
|     :alt: Downloads |     :alt: Downloads | ||||||
|     :target: https://pepy.tech/project/sanic |     :target: https://pepy.tech/project/sanic | ||||||
| .. |Conda downloads| image:: https://img.shields.io/conda/dn/conda-forge/sanic.svg | .. |Conda downloads| image:: https://img.shields.io/conda/dn/conda-forge/sanic.svg | ||||||
|     :alt: Downloads |     :alt: Downloads | ||||||
|     :target: https://anaconda.org/conda-forge/sanic |     :target: https://anaconda.org/conda-forge/sanic | ||||||
| .. |Linode| image:: https://www.linode.com/wp-content/uploads/2021/01/Linode-Logo-Black.svg |  | ||||||
|     :alt: Linode |  | ||||||
|     :target: https://www.linode.com |  | ||||||
|     :width: 200px |  | ||||||
|  |  | ||||||
| .. end-badges | .. end-badges | ||||||
|  |  | ||||||
| Sanic is a **Python 3.8+** web server and web framework that's written to go fast. It allows the usage of the ``async/await`` syntax added in Python 3.5, which makes your code non-blocking and speedy. | Sanic is a **Python 3.7+** web server and web framework that's written to go fast. It allows the usage of the ``async/await`` syntax added in Python 3.5, which makes your code non-blocking and speedy. | ||||||
|  |  | ||||||
| Sanic is also ASGI compliant, so you can deploy it with an `alternative ASGI webserver <https://sanicframework.org/en/guide/deployment/running.html#asgi>`_. | Sanic is also ASGI compliant, so you can deploy it with an `alternative ASGI webserver <https://sanicframework.org/en/guide/deployment/running.html#asgi>`_. | ||||||
|  |  | ||||||
| @@ -79,7 +77,7 @@ The goal of the project is to provide a simple way to get up and running a highl | |||||||
| Sponsor | Sponsor | ||||||
| ------- | ------- | ||||||
|  |  | ||||||
| Check out `open collective <https://opencollective.com/sanic-org>`_ to learn more about helping to fund Sanic. | Check out `open collective <https://opencollective.com/sanic-org>`_ to learn more about helping to fund Sanic.  | ||||||
|  |  | ||||||
| Thanks to `Linode <https://www.linode.com>`_ for their contribution towards the development and community of Sanic. | Thanks to `Linode <https://www.linode.com>`_ for their contribution towards the development and community of Sanic. | ||||||
|  |  | ||||||
| @@ -143,17 +141,17 @@ And, we can verify it is working: ``curl localhost:8000 -i`` | |||||||
|  |  | ||||||
| **Now, let's go build something fast!** | **Now, let's go build something fast!** | ||||||
|  |  | ||||||
| Minimum Python version is 3.8. If you need Python 3.7 support, please use v22.12LTS. | Minimum Python version is 3.7. If you need Python 3.6 support, please use v20.12LTS. | ||||||
|  |  | ||||||
| Documentation | Documentation | ||||||
| ------------- | ------------- | ||||||
|  |  | ||||||
| `User Guide <https://sanic.dev>`__ and `API Documentation <http://sanic.readthedocs.io/>`__. | `User Guide <https://sanicframework.org>`__ and `API Documentation <http://sanic.readthedocs.io/>`__. | ||||||
|  |  | ||||||
| Changelog | Changelog | ||||||
| --------- | --------- | ||||||
|  |  | ||||||
| `Release Changelogs <https://sanic.readthedocs.io/en/stable/sanic/changelog.html>`__. | `Release Changelogs <https://github.com/sanic-org/sanic/blob/master/CHANGELOG.rst>`__. | ||||||
|  |  | ||||||
|  |  | ||||||
| Questions and Discussion | Questions and Discussion | ||||||
| @@ -165,3 +163,8 @@ Contribution | |||||||
| ------------ | ------------ | ||||||
|  |  | ||||||
| We are always happy to have new contributions. We have `marked issues good for anyone looking to get started <https://github.com/sanic-org/sanic/issues?q=is%3Aopen+is%3Aissue+label%3Abeginner>`_, and welcome `questions on the forums <https://community.sanicframework.org/>`_. Please take a look at our `Contribution guidelines <https://github.com/sanic-org/sanic/blob/master/CONTRIBUTING.rst>`_. | We are always happy to have new contributions. We have `marked issues good for anyone looking to get started <https://github.com/sanic-org/sanic/issues?q=is%3Aopen+is%3Aissue+label%3Abeginner>`_, and welcome `questions on the forums <https://community.sanicframework.org/>`_. Please take a look at our `Contribution guidelines <https://github.com/sanic-org/sanic/blob/master/CONTRIBUTING.rst>`_. | ||||||
|  |  | ||||||
|  | .. |Linode| image:: https://www.linode.com/wp-content/uploads/2021/01/Linode-Logo-Black.svg | ||||||
|  |     :alt: Linode | ||||||
|  |     :target: https://www.linode.com | ||||||
|  |     :width: 200px | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								sanic/app.py
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								sanic/app.py
									
									
									
									
									
								
							| @@ -5,6 +5,7 @@ import logging | |||||||
| import logging.config | import logging.config | ||||||
| import re | import re | ||||||
| import sys | import sys | ||||||
|  |  | ||||||
| from asyncio import ( | from asyncio import ( | ||||||
|     AbstractEventLoop, |     AbstractEventLoop, | ||||||
|     CancelledError, |     CancelledError, | ||||||
| @@ -93,6 +94,7 @@ from sanic.worker.inspector import Inspector | |||||||
| from sanic.worker.loader import CertLoader | from sanic.worker.loader import CertLoader | ||||||
| from sanic.worker.manager import WorkerManager | from sanic.worker.manager import WorkerManager | ||||||
|  |  | ||||||
|  |  | ||||||
| if TYPE_CHECKING: | if TYPE_CHECKING: | ||||||
|     try: |     try: | ||||||
|         from sanic_ext import Extend  # type: ignore |         from sanic_ext import Extend  # type: ignore | ||||||
| @@ -1741,20 +1743,6 @@ class Sanic( | |||||||
|         if hasattr(self, "multiplexer"): |         if hasattr(self, "multiplexer"): | ||||||
|             self.multiplexer.ack() |             self.multiplexer.ack() | ||||||
|  |  | ||||||
|     def set_serving(self, serving: bool) -> None: |  | ||||||
|         """Set the serving state of the application. |  | ||||||
|  |  | ||||||
|         This method is used to set the serving state of the application. |  | ||||||
|         It is used internally by Sanic and should not typically be called |  | ||||||
|         manually. |  | ||||||
|  |  | ||||||
|         Args: |  | ||||||
|             serving (bool): Whether the application is serving. |  | ||||||
|         """ |  | ||||||
|         self.state.is_running = serving |  | ||||||
|         if hasattr(self, "multiplexer"): |  | ||||||
|             self.multiplexer.set_serving(serving) |  | ||||||
|  |  | ||||||
|     async def _server_event( |     async def _server_event( | ||||||
|         self, |         self, | ||||||
|         concern: str, |         concern: str, | ||||||
|   | |||||||
| @@ -73,6 +73,14 @@ class MOTDTTY(MOTD): | |||||||
|             self.value_width = min( |             self.value_width = min( | ||||||
|                 max(map(len, self.data.values())), self.max_value_width |                 max(map(len, self.data.values())), self.max_value_width | ||||||
|             ) |             ) | ||||||
|  |         if self.extra: | ||||||
|  |             self.key_width = max( | ||||||
|  |                 self.key_width, max(map(len, self.extra.keys())) | ||||||
|  |             ) | ||||||
|  |             self.value_width = min( | ||||||
|  |                 max((*map(len, self.extra.values()), self.value_width)), | ||||||
|  |                 self.max_value_width, | ||||||
|  |             ) | ||||||
|         self.logo_lines = self.logo.split("\n") if self.logo else [] |         self.logo_lines = self.logo.split("\n") if self.logo else [] | ||||||
|         self.logo_line_length = 24 |         self.logo_line_length = 24 | ||||||
|         self.centering_length = ( |         self.centering_length = ( | ||||||
| @@ -104,7 +112,7 @@ class MOTDTTY(MOTD): | |||||||
|         self._render_data(lines, self.data, 0) |         self._render_data(lines, self.data, 0) | ||||||
|         if self.extra: |         if self.extra: | ||||||
|             logo_part = self._get_logo_part(len(lines) - 4) |             logo_part = self._get_logo_part(len(lines) - 4) | ||||||
|             lines.append(f"| {logo_part} ├{display_filler}┤") |             lines.append(f"│ {logo_part} ├{display_filler}┤") | ||||||
|             self._render_data(lines, self.extra, len(lines) - 4) |             self._render_data(lines, self.extra, len(lines) - 4) | ||||||
|  |  | ||||||
|         self._render_fill(lines) |         self._render_fill(lines) | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ from __future__ import annotations | |||||||
| import os | import os | ||||||
| import platform | import platform | ||||||
| import sys | import sys | ||||||
|  |  | ||||||
| from asyncio import ( | from asyncio import ( | ||||||
|     AbstractEventLoop, |     AbstractEventLoop, | ||||||
|     CancelledError, |     CancelledError, | ||||||
| @@ -64,13 +65,13 @@ from sanic.server.protocols.http_protocol import HttpProtocol | |||||||
| from sanic.server.protocols.websocket_protocol import WebSocketProtocol | from sanic.server.protocols.websocket_protocol import WebSocketProtocol | ||||||
| from sanic.server.runners import serve | from sanic.server.runners import serve | ||||||
| from sanic.server.socket import configure_socket, remove_unix_socket | from sanic.server.socket import configure_socket, remove_unix_socket | ||||||
| from sanic.worker.constants import ProcessState |  | ||||||
| from sanic.worker.loader import AppLoader | from sanic.worker.loader import AppLoader | ||||||
| from sanic.worker.manager import WorkerManager | from sanic.worker.manager import WorkerManager | ||||||
| from sanic.worker.multiplexer import WorkerMultiplexer | from sanic.worker.multiplexer import WorkerMultiplexer | ||||||
| from sanic.worker.reloader import Reloader | from sanic.worker.reloader import Reloader | ||||||
| from sanic.worker.serve import worker_serve | from sanic.worker.serve import worker_serve | ||||||
|  |  | ||||||
|  |  | ||||||
| if TYPE_CHECKING: | if TYPE_CHECKING: | ||||||
|     from sanic import Sanic |     from sanic import Sanic | ||||||
|     from sanic.application.state import ApplicationState |     from sanic.application.state import ApplicationState | ||||||
| @@ -89,6 +90,7 @@ else:  # no cov | |||||||
| class StartupMixin(metaclass=SanicMeta): | class StartupMixin(metaclass=SanicMeta): | ||||||
|     _app_registry: ClassVar[Dict[str, Sanic]] |     _app_registry: ClassVar[Dict[str, Sanic]] | ||||||
|  |  | ||||||
|  |     name: str | ||||||
|     config: Config |     config: Config | ||||||
|     listeners: Dict[str, List[ListenerType[Any]]] |     listeners: Dict[str, List[ListenerType[Any]]] | ||||||
|     state: ApplicationState |     state: ApplicationState | ||||||
| @@ -604,6 +606,7 @@ class StartupMixin(metaclass=SanicMeta): | |||||||
|             server = "ASGI" if self.asgi else "unknown"  # type: ignore |             server = "ASGI" if self.asgi else "unknown"  # type: ignore | ||||||
|  |  | ||||||
|         display = { |         display = { | ||||||
|  |             "app": self.name, | ||||||
|             "mode": " ".join(mode), |             "mode": " ".join(mode), | ||||||
|             "server": server, |             "server": server, | ||||||
|             "python": platform.python_version(), |             "python": platform.python_version(), | ||||||
| @@ -892,6 +895,7 @@ class StartupMixin(metaclass=SanicMeta): | |||||||
|                 app.router.reset() |                 app.router.reset() | ||||||
|                 app.signal_router.reset() |                 app.signal_router.reset() | ||||||
|  |  | ||||||
|  |             sync_manager.shutdown() | ||||||
|             for sock in socks: |             for sock in socks: | ||||||
|                 try: |                 try: | ||||||
|                     sock.shutdown(SHUT_RDWR) |                     sock.shutdown(SHUT_RDWR) | ||||||
| @@ -903,33 +907,12 @@ class StartupMixin(metaclass=SanicMeta): | |||||||
|             loop.close() |             loop.close() | ||||||
|             cls._cleanup_env_vars() |             cls._cleanup_env_vars() | ||||||
|             cls._cleanup_apps() |             cls._cleanup_apps() | ||||||
|  |  | ||||||
|             from time import sleep |  | ||||||
|  |  | ||||||
|             limit = 100 |  | ||||||
|             while cls._get_process_states(worker_state): |  | ||||||
|                 sleep(0.1) |  | ||||||
|                 limit -= 1 |  | ||||||
|                 if limit <= 0: |  | ||||||
|                     error_logger.warning( |  | ||||||
|                         "Worker shutdown timed out. " |  | ||||||
|                         "Some processes may still be running." |  | ||||||
|                     ) |  | ||||||
|                     break |  | ||||||
|             sync_manager.shutdown() |  | ||||||
|             unix = kwargs.get("unix") |             unix = kwargs.get("unix") | ||||||
|             if unix: |             if unix: | ||||||
|                 remove_unix_socket(unix) |                 remove_unix_socket(unix) | ||||||
|             logger.info("Goodbye.") |  | ||||||
|         if exit_code: |         if exit_code: | ||||||
|             os._exit(exit_code) |             os._exit(exit_code) | ||||||
|  |  | ||||||
|     @staticmethod |  | ||||||
|     def _get_process_states(worker_state) -> List[str]: |  | ||||||
|         return [ |  | ||||||
|             state for s in worker_state.values() if (state := s.get("state")) |  | ||||||
|         ] |  | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def serve_single(cls, primary: Optional[Sanic] = None) -> None: |     def serve_single(cls, primary: Optional[Sanic] = None) -> None: | ||||||
|         os.environ["SANIC_MOTD_OUTPUT"] = "true" |         os.environ["SANIC_MOTD_OUTPUT"] = "true" | ||||||
|   | |||||||
| @@ -122,15 +122,17 @@ def _setup_system_signals( | |||||||
|     register_sys_signals: bool, |     register_sys_signals: bool, | ||||||
|     loop: asyncio.AbstractEventLoop, |     loop: asyncio.AbstractEventLoop, | ||||||
| ) -> None:  # no cov | ) -> None:  # no cov | ||||||
|     signal_func(SIGINT, SIG_IGN) |     # Ignore SIGINT when run_multiple | ||||||
|     signal_func(SIGTERM, SIG_IGN) |     if run_multiple: | ||||||
|     os.environ["SANIC_WORKER_PROCESS"] = "true" |         signal_func(SIGINT, SIG_IGN) | ||||||
|  |         os.environ["SANIC_WORKER_PROCESS"] = "true" | ||||||
|  |  | ||||||
|     # Register signals for graceful termination |     # Register signals for graceful termination | ||||||
|     if register_sys_signals: |     if register_sys_signals: | ||||||
|         if OS_IS_WINDOWS: |         if OS_IS_WINDOWS: | ||||||
|             ctrlc_workaround_for_windows(app) |             ctrlc_workaround_for_windows(app) | ||||||
|         else: |         else: | ||||||
|             for _signal in [SIGINT, SIGTERM]: |             for _signal in [SIGTERM] if run_multiple else [SIGINT, SIGTERM]: | ||||||
|                 loop.add_signal_handler( |                 loop.add_signal_handler( | ||||||
|                     _signal, partial(app.stop, terminate=False) |                     _signal, partial(app.stop, terminate=False) | ||||||
|                 ) |                 ) | ||||||
| @@ -141,6 +143,8 @@ def _run_server_forever(loop, before_stop, after_stop, cleanup, unix): | |||||||
|     try: |     try: | ||||||
|         server_logger.info("Starting worker [%s]", pid) |         server_logger.info("Starting worker [%s]", pid) | ||||||
|         loop.run_forever() |         loop.run_forever() | ||||||
|  |     except KeyboardInterrupt: | ||||||
|  |         pass | ||||||
|     finally: |     finally: | ||||||
|         server_logger.info("Stopping worker [%s]", pid) |         server_logger.info("Stopping worker [%s]", pid) | ||||||
|  |  | ||||||
| @@ -152,7 +156,6 @@ def _run_server_forever(loop, before_stop, after_stop, cleanup, unix): | |||||||
|         loop.run_until_complete(after_stop()) |         loop.run_until_complete(after_stop()) | ||||||
|         remove_unix_socket(unix) |         remove_unix_socket(unix) | ||||||
|         loop.close() |         loop.close() | ||||||
|         server_logger.info("Worker complete [%s]", pid) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def _serve_http_1( | def _serve_http_1( | ||||||
| @@ -256,11 +259,8 @@ def _serve_http_1( | |||||||
|             else: |             else: | ||||||
|                 conn.abort() |                 conn.abort() | ||||||
|  |  | ||||||
|         app.set_serving(False) |  | ||||||
|  |  | ||||||
|     _setup_system_signals(app, run_multiple, register_sys_signals, loop) |     _setup_system_signals(app, run_multiple, register_sys_signals, loop) | ||||||
|     loop.run_until_complete(app._server_event("init", "after")) |     loop.run_until_complete(app._server_event("init", "after")) | ||||||
|     app.set_serving(True) |  | ||||||
|     _run_server_forever( |     _run_server_forever( | ||||||
|         loop, |         loop, | ||||||
|         partial(app._server_event, "shutdown", "before"), |         partial(app._server_event, "shutdown", "before"), | ||||||
|   | |||||||
| @@ -122,7 +122,6 @@ class WorkerManager: | |||||||
|         self.monitor() |         self.monitor() | ||||||
|         self.join() |         self.join() | ||||||
|         self.terminate() |         self.terminate() | ||||||
|         self.cleanup() |  | ||||||
|  |  | ||||||
|     def start(self): |     def start(self): | ||||||
|         for process in self.processes: |         for process in self.processes: | ||||||
| @@ -148,11 +147,6 @@ class WorkerManager: | |||||||
|             for process in self.processes: |             for process in self.processes: | ||||||
|                 process.terminate() |                 process.terminate() | ||||||
|  |  | ||||||
|     def cleanup(self): |  | ||||||
|         """Cleanup the worker processes.""" |  | ||||||
|         for process in self.processes: |  | ||||||
|             process.exit() |  | ||||||
|  |  | ||||||
|     def restart( |     def restart( | ||||||
|         self, |         self, | ||||||
|         process_names: Optional[List[str]] = None, |         process_names: Optional[List[str]] = None, | ||||||
|   | |||||||
| @@ -28,24 +28,6 @@ class WorkerMultiplexer: | |||||||
|             "state": ProcessState.ACKED.name, |             "state": ProcessState.ACKED.name, | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     def set_serving(self, serving: bool) -> None: |  | ||||||
|         """Set the worker to serving. |  | ||||||
|  |  | ||||||
|         Args: |  | ||||||
|             serving (bool): Whether the worker is serving. |  | ||||||
|         """ |  | ||||||
|         self._state._state[self.name] = { |  | ||||||
|             **self._state._state[self.name], |  | ||||||
|             "serving": serving, |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     def exit(self): |  | ||||||
|         """Run cleanup at worker exit.""" |  | ||||||
|         try: |  | ||||||
|             del self._state._state[self.name] |  | ||||||
|         except ConnectionRefusedError: |  | ||||||
|             logger.debug("Monitor process has already exited.") |  | ||||||
|  |  | ||||||
|     def restart( |     def restart( | ||||||
|         self, |         self, | ||||||
|         name: str = "", |         name: str = "", | ||||||
|   | |||||||
| @@ -65,20 +65,6 @@ class WorkerProcess: | |||||||
|         self.set_state(ProcessState.JOINED) |         self.set_state(ProcessState.JOINED) | ||||||
|         self._current_process.join() |         self._current_process.join() | ||||||
|  |  | ||||||
|     def exit(self): |  | ||||||
|         limit = 100 |  | ||||||
|         while self.is_alive() and limit > 0: |  | ||||||
|             sleep(0.1) |  | ||||||
|             limit -= 1 |  | ||||||
|  |  | ||||||
|         if not self.is_alive(): |  | ||||||
|             try: |  | ||||||
|                 del self.worker_state[self.name] |  | ||||||
|             except ConnectionRefusedError: |  | ||||||
|                 logger.debug("Monitor process has already exited.") |  | ||||||
|             except KeyError: |  | ||||||
|                 logger.debug("Could not find worker state to delete.") |  | ||||||
|  |  | ||||||
|     def terminate(self): |     def terminate(self): | ||||||
|         if self.state is not ProcessState.TERMINATED: |         if self.state is not ProcessState.TERMINATED: | ||||||
|             logger.debug( |             logger.debug( | ||||||
| @@ -91,6 +77,7 @@ class WorkerProcess: | |||||||
|             self.set_state(ProcessState.TERMINATED, force=True) |             self.set_state(ProcessState.TERMINATED, force=True) | ||||||
|             try: |             try: | ||||||
|                 os.kill(self.pid, SIGINT) |                 os.kill(self.pid, SIGINT) | ||||||
|  |                 del self.worker_state[self.name] | ||||||
|             except (KeyError, AttributeError, ProcessLookupError): |             except (KeyError, AttributeError, ProcessLookupError): | ||||||
|                 ... |                 ... | ||||||
|  |  | ||||||
| @@ -131,16 +118,6 @@ class WorkerProcess: | |||||||
|         except AssertionError: |         except AssertionError: | ||||||
|             return False |             return False | ||||||
|  |  | ||||||
|     # def _run(self, **kwargs): |  | ||||||
|     #     atexit.register(self._exit) |  | ||||||
|     #     self.target(**kwargs) |  | ||||||
|  |  | ||||||
|     # def _exit(self): |  | ||||||
|     #     try: |  | ||||||
|     #         del self.worker_state[self.name] |  | ||||||
|     #     except ConnectionRefusedError: |  | ||||||
|     #         logger.debug("Monitor process has already exited.") |  | ||||||
|  |  | ||||||
|     def spawn(self): |     def spawn(self): | ||||||
|         if self.state not in (ProcessState.IDLE, ProcessState.RESTARTING): |         if self.state not in (ProcessState.IDLE, ProcessState.RESTARTING): | ||||||
|             raise Exception("Cannot spawn a worker process until it is idle.") |             raise Exception("Cannot spawn a worker process until it is idle.") | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								setup.py
									
									
									
									
									
								
							| @@ -143,7 +143,6 @@ docs_require = [ | |||||||
|     "m2r2", |     "m2r2", | ||||||
|     "enum-tools[sphinx]", |     "enum-tools[sphinx]", | ||||||
|     "mistune<2.0.0", |     "mistune<2.0.0", | ||||||
|     "autodocsumm>=0.2.11", |  | ||||||
| ] | ] | ||||||
|  |  | ||||||
| dev_require = tests_require + [ | dev_require = tests_require + [ | ||||||
|   | |||||||
| @@ -31,10 +31,11 @@ def test_motd_with_expected_info(app, run_startup): | |||||||
|     logs = run_startup(app) |     logs = run_startup(app) | ||||||
|  |  | ||||||
|     assert logs[1][2] == f"Sanic v{__version__}" |     assert logs[1][2] == f"Sanic v{__version__}" | ||||||
|     assert logs[3][2] == "mode: debug, single worker" |     assert logs[3][2] == "app: test_motd_with_expected_info" | ||||||
|     assert logs[4][2] == "server: sanic, HTTP/1.1" |     assert logs[4][2] == "mode: debug, single worker" | ||||||
|     assert logs[5][2] == f"python: {platform.python_version()}" |     assert logs[5][2] == "server: sanic, HTTP/1.1" | ||||||
|     assert logs[6][2] == f"platform: {platform.platform()}" |     assert logs[6][2] == f"python: {platform.python_version()}" | ||||||
|  |     assert logs[7][2] == f"platform: {platform.platform()}" | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_motd_init(): | def test_motd_init(): | ||||||
| @@ -61,7 +62,7 @@ def test_motd_display(caplog): | |||||||
|   │                                │ |   │                                │ | ||||||
|   ├───────────────────────┬────────┤ |   ├───────────────────────┬────────┤ | ||||||
|   │        foobar         │ one: 1 │ |   │        foobar         │ one: 1 │ | ||||||
|   |                       ├────────┤ |   │                       ├────────┤ | ||||||
|   │                       │ two: 2 │ |   │                       │ two: 2 │ | ||||||
|   └───────────────────────┴────────┘ |   └───────────────────────┴────────┘ | ||||||
| """ | """ | ||||||
|   | |||||||
| @@ -517,7 +517,7 @@ def test_stack_trace_on_not_found(app, static_file_directory, caplog): | |||||||
|     counter = Counter([(r[0], r[1]) for r in caplog.record_tuples]) |     counter = Counter([(r[0], r[1]) for r in caplog.record_tuples]) | ||||||
|  |  | ||||||
|     assert response.status == 404 |     assert response.status == 404 | ||||||
|     assert counter[("sanic.root", logging.INFO)] == 9 |     assert counter[("sanic.root", logging.INFO)] == 10 | ||||||
|     assert counter[("sanic.root", logging.ERROR)] == 0 |     assert counter[("sanic.root", logging.ERROR)] == 0 | ||||||
|     assert counter[("sanic.error", logging.ERROR)] == 0 |     assert counter[("sanic.error", logging.ERROR)] == 0 | ||||||
|     assert counter[("sanic.server", logging.INFO)] == 2 |     assert counter[("sanic.server", logging.INFO)] == 2 | ||||||
| @@ -536,7 +536,7 @@ def test_no_stack_trace_on_not_found(app, static_file_directory, caplog): | |||||||
|     counter = Counter([(r[0], r[1]) for r in caplog.record_tuples]) |     counter = Counter([(r[0], r[1]) for r in caplog.record_tuples]) | ||||||
|  |  | ||||||
|     assert response.status == 404 |     assert response.status == 404 | ||||||
|     assert counter[("sanic.root", logging.INFO)] == 9 |     assert counter[("sanic.root", logging.INFO)] == 10 | ||||||
|     assert counter[("sanic.root", logging.ERROR)] == 0 |     assert counter[("sanic.root", logging.ERROR)] == 0 | ||||||
|     assert counter[("sanic.error", logging.ERROR)] == 0 |     assert counter[("sanic.error", logging.ERROR)] == 0 | ||||||
|     assert counter[("sanic.server", logging.INFO)] == 2 |     assert counter[("sanic.server", logging.INFO)] == 2 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user