Compare commits
5 Commits
smoother-p
...
motd-fixes
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44bf7ba79a | ||
|
|
9e7ca10c52 | ||
|
|
fe32f4eb74 | ||
|
|
ebe29d3d26 | ||
|
|
f651f7436f |
27
README.rst
27
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>`_.
|
||||||
|
|
||||||
@@ -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