Skip to content

Commit

Permalink
fix(uvicorn): review
Browse files Browse the repository at this point in the history
  • Loading branch information
Alviner committed Nov 19, 2023
1 parent 7737218 commit b39c2f0
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 88 deletions.
6 changes: 0 additions & 6 deletions aiomisc/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,6 @@ def time_ns() -> int:
else:
from typing_extensions import Protocol

if sys.version_info >= (3, 8):
from typing import TypedDict
else:
from typing_extensions import TypedDict


class EntrypointProtocol(Protocol):
@property
Expand Down Expand Up @@ -123,7 +118,6 @@ def sock_set_reuseport(sock: socket.socket, reuse_port: bool) -> None:
"EventLoopMixin",
"ParamSpec",
"Protocol",
"TypedDict",
"entry_pont_iterator",
"event_loop_policy",
"final",
Expand Down
159 changes: 80 additions & 79 deletions aiomisc/service/uvicorn.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,17 @@
import asyncio
import logging
import os
import signal
import socket
from typing import (
Any, Awaitable, Callable, List, Optional, Tuple, Type, Union, cast,
)
import ssl
from typing import Any, Awaitable, Callable, List, Optional, Tuple, Type, Union

from asgiref.typing import ASGIApplication
from uvicorn.server import Server
from uvicorn.config import (
HTTPProtocolType, InterfaceType, LifespanType, LoopSetupType,
WSProtocolType, Config
SSL_PROTOCOL_VERSION, Config, HTTPProtocolType, InterfaceType, LifespanType,
WSProtocolType,
)
from uvicorn.server import Server

from aiomisc.compat import TypedDict
from aiomisc.service import Service


Expand All @@ -24,44 +21,6 @@
UvicornApplication = Union[ASGIApplication, Callable]


class ConfigKwargs(TypedDict, total=False):
host: str
port: int
uds: Optional[str]
fd: Optional[int]
loop: LoopSetupType
http: Union[Type[asyncio.Protocol], HTTPProtocolType]
ws: Union[Type[asyncio.Protocol], WSProtocolType]
ws_max_size: int
ws_ping_interval: Optional[float]
ws_ping_timeout: Optional[float]
ws_per_message_deflate: bool
lifespan: LifespanType
access_log: bool
interface: InterfaceType
proxy_headers: bool
server_header: bool
date_header: bool
forwarded_allow_ips: Optional[Union[List[str], str]]
root_path: str
limit_concurrency: Optional[int]
limit_max_requests: Optional[int]
backlog: int
timeout_keep_alive: int
timeout_notify: int
timeout_graceful_shutdown: Optional[int]
callback_notify: Optional[Callable[..., Awaitable[None]]]
ssl_keyfile: Optional[str]
ssl_certfile: Optional[Union[str, os.PathLike]]
ssl_keyfile_password: Optional[str]
ssl_version: int
ssl_cert_reqs: int
ssl_ca_certs: Optional[str]
ssl_ciphers: str
headers: Optional[List[Tuple[str, str]]]
h11_max_incomplete_event_size: Optional[int]


class UvicornService(Service, abc.ABC):
__async_required__: Tuple[str, ...] = (
"start",
Expand All @@ -70,24 +29,42 @@ class UvicornService(Service, abc.ABC):

sock: Optional[socket.socket] = None

server: Server
runner: Optional[asyncio.Task] = None

def __init__(
self,
sock: Optional[socket.socket] = None,
config_kwargs: Optional[ConfigKwargs] = None,
**kwargs: Any,
):
self.sock = sock
host: str = "127.0.0.1"
port: int = 8080
uds: Optional[str] = None
fd: Optional[int] = None
http: Union[Type[asyncio.Protocol], HTTPProtocolType] = "auto"
ws: Union[Type[asyncio.Protocol], WSProtocolType] = "auto"
ws_max_size: int = 16 * 1024 * 1024
ws_ping_interval: Optional[float] = 20.0
ws_ping_timeout: Optional[float] = 20.0
ws_per_message_deflate: bool = True
lifespan: LifespanType = "auto"
access_log: bool = True
interface: InterfaceType = "auto"
proxy_headers: bool = True
server_header: bool = True
date_header: bool = True
forwarded_allow_ips: Optional[Union[List[str], str]] = None
root_path: str = ""
limit_concurrency: Optional[int] = None
limit_max_requests: Optional[int] = None
backlog: int = 2048
timeout_keep_alive: int = 5
timeout_notify: int = 30
timeout_graceful_shutdown: Optional[int] = None
callback_notify: Optional[Callable[..., Awaitable[None]]] = None
ssl_keyfile: Optional[str] = None
ssl_certfile: Optional[Union[str, os.PathLike]] = None
ssl_keyfile_password: Optional[str] = None
ssl_version: int = SSL_PROTOCOL_VERSION
ssl_cert_reqs: int = ssl.CERT_NONE
ssl_ca_certs: Optional[str] = None
ssl_ciphers: str = "TLSv1"
headers: Optional[List[Tuple[str, str]]] = None
factory: bool = False
h11_max_incomplete_event_size: Optional[int] = None

config_kwargs = cast(ConfigKwargs, dict(config_kwargs or dict()))
config_kwargs.setdefault("access_log", True)
config_kwargs.setdefault("host", "127.0.0.1")
config_kwargs.setdefault("port", 8080)

self.config_kwargs = config_kwargs
super().__init__(**kwargs)

@abc.abstractmethod
async def create_application(self) -> UvicornApplication:
Expand All @@ -98,25 +75,49 @@ async def start(self) -> Any:

config = Config(
app,
host=self.host,
port=self.port,
uds=self.uds,
fd=self.fd,
http=self.http,
ws=self.ws,
ws_max_size=self.ws_max_size,
ws_ping_interval=self.ws_ping_interval,
ws_ping_timeout=self.ws_ping_timeout,
ws_per_message_deflate=self.ws_per_message_deflate,
lifespan=self.lifespan,
access_log=self.access_log,
interface=self.interface,
proxy_headers=self.proxy_headers,
server_header=self.server_header,
date_header=self.date_header,
forwarded_allow_ips=self.forwarded_allow_ips,
root_path=self.root_path,
limit_concurrency=self.limit_concurrency,
limit_max_requests=self.limit_max_requests,
backlog=self.backlog,
timeout_keep_alive=self.timeout_keep_alive,
timeout_notify=self.timeout_notify,
timeout_graceful_shutdown=self.timeout_graceful_shutdown,
callback_notify=self.callback_notify,
ssl_keyfile=self.ssl_keyfile,
ssl_certfile=self.ssl_certfile,
ssl_keyfile_password=self.ssl_keyfile_password,
ssl_version=self.ssl_version,
ssl_cert_reqs=self.ssl_cert_reqs,
ssl_ca_certs=self.ssl_ca_certs,
ssl_ciphers=self.ssl_ciphers,
headers=self.headers,
factory=self.factory,
h11_max_incomplete_event_size=self.h11_max_incomplete_event_size,
log_config=None,
use_colors=False,
**self.config_kwargs,
)
if not self.sock:
self.sock = config.bind_socket()
self.server = Server(config)
self.runner = asyncio.create_task(
self.server.serve(sockets=[self.sock])
)
return None
server = Server(config)

async def stop(self, exception: Optional[Exception] = None) -> Any:
if not self.runner:
return
try:
self.server.handle_exit(signal.SIGINT, frame=None)
await self.runner
except Exception:
log.error("Cannot graceful shutdown serve task")
self.runner.cancel()
return await super().stop(exception)
self.start_event.set()

await server.serve(sockets=[self.sock])
return None
2 changes: 1 addition & 1 deletion docs/source/services.rst
Original file line number Diff line number Diff line change
Expand Up @@ -719,7 +719,7 @@ Any ASGI-like application can be started via uvicorn as a service:
arguments = parser.parse_args()
service = REST(config_kwargs=dict(host=arguments.host, port=arguments.port))
service = REST(host=arguments.host, port=arguments.port)
with entrypoint(service) as loop:
loop.run_forever()
Expand Down
4 changes: 2 additions & 2 deletions tests/test_entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@
from aiomisc.entrypoint import Entrypoint, entrypoint
from aiomisc.service import TCPServer, TLSServer, UDPServer
from aiomisc.service.aiohttp import AIOHTTPService
from aiomisc.service.uvicorn import UvicornApplication, UvicornService
from aiomisc.service.asgi import ASGIApplicationType, ASGIHTTPService
from aiomisc.service.grpc_server import GRPCService
from aiomisc.service.tcp import RobustTCPClient, TCPClient
from aiomisc.service.tls import RobustTLSClient, TLSClient
from aiomisc.service.uvicorn import UvicornApplication, UvicornService
from aiomisc_log import LogFormat
from aiomisc_log.enum import DateFormat, LogLevel
from tests import unix_only
Expand Down Expand Up @@ -708,7 +708,7 @@ async def http_client():
return response.status, await response.json()

service = UvicornTestService(
config_kwargs=dict(host="127.0.0.1", port=aiomisc_unused_port),
host="127.0.0.1", port=aiomisc_unused_port,
)

with aiomisc.entrypoint(service) as loop:
Expand Down

0 comments on commit b39c2f0

Please sign in to comment.