forked from aegis/pyserveX
cython path_matcher added to reduce time on hot operations
This commit is contained in:
+33
-68
@@ -1,18 +1,19 @@
|
||||
import ssl
|
||||
import uvicorn
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
import uvicorn
|
||||
from starlette.applications import Starlette
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import Response, PlainTextResponse
|
||||
from starlette.responses import PlainTextResponse, Response
|
||||
from starlette.routing import Route
|
||||
from starlette.types import ASGIApp, Receive, Scope, Send
|
||||
from pathlib import Path
|
||||
from typing import Optional, Dict, Any
|
||||
|
||||
from .config import Config
|
||||
from .extensions import ExtensionManager, ASGIExtension
|
||||
from .logging_utils import get_logger
|
||||
from . import __version__
|
||||
from .config import Config
|
||||
from .extensions import ASGIExtension, ExtensionManager
|
||||
from .logging_utils import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
@@ -21,7 +22,7 @@ class PyServeMiddleware:
|
||||
def __init__(self, app: ASGIApp, extension_manager: ExtensionManager):
|
||||
self.app = app
|
||||
self.extension_manager = extension_manager
|
||||
self.access_logger = get_logger('pyserve.access')
|
||||
self.access_logger = get_logger("pyserve.access")
|
||||
|
||||
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
|
||||
if scope["type"] != "http":
|
||||
@@ -48,14 +49,7 @@ class PyServeMiddleware:
|
||||
|
||||
await response(scope, receive, send)
|
||||
|
||||
async def _try_asgi_mount(
|
||||
self,
|
||||
scope: Scope,
|
||||
receive: Receive,
|
||||
send: Send,
|
||||
request: Request,
|
||||
start_time: float
|
||||
) -> bool:
|
||||
async def _try_asgi_mount(self, scope: Scope, receive: Receive, send: Send, request: Request, start_time: float) -> bool:
|
||||
for extension in self.extension_manager.extensions:
|
||||
if isinstance(extension, ASGIExtension):
|
||||
mount = extension.get_asgi_handler(request)
|
||||
@@ -65,10 +59,7 @@ class PyServeMiddleware:
|
||||
modified_scope["path"] = mount.get_modified_path(request.url.path)
|
||||
modified_scope["root_path"] = scope.get("root_path", "") + mount.path
|
||||
|
||||
logger.debug(
|
||||
f"Routing to ASGI mount '{mount.name}': "
|
||||
f"{request.url.path} -> {modified_scope['path']}"
|
||||
)
|
||||
logger.debug(f"Routing to ASGI mount '{mount.name}': " f"{request.url.path} -> {modified_scope['path']}")
|
||||
|
||||
try:
|
||||
response_started = False
|
||||
@@ -92,15 +83,12 @@ class PyServeMiddleware:
|
||||
mount=mount.name,
|
||||
status_code=status_code,
|
||||
process_time_ms=process_time,
|
||||
user_agent=request.headers.get("user-agent", "")
|
||||
user_agent=request.headers.get("user-agent", ""),
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Error in ASGI mount '{mount.name}': {e}")
|
||||
error_response = PlainTextResponse(
|
||||
"500 Internal Server Error",
|
||||
status_code=500
|
||||
)
|
||||
error_response = PlainTextResponse("500 Internal Server Error", status_code=500)
|
||||
await error_response(scope, receive, send)
|
||||
return True
|
||||
return False
|
||||
@@ -122,7 +110,7 @@ class PyServeMiddleware:
|
||||
path=path,
|
||||
status_code=status_code,
|
||||
process_time_ms=process_time,
|
||||
user_agent=request.headers.get("user-agent", "")
|
||||
user_agent=request.headers.get("user-agent", ""),
|
||||
)
|
||||
|
||||
|
||||
@@ -145,27 +133,13 @@ class PyServeServer:
|
||||
if ext_config.type == "routing":
|
||||
config.setdefault("default_proxy_timeout", self.config.server.proxy_timeout)
|
||||
|
||||
self.extension_manager.load_extension(
|
||||
ext_config.type,
|
||||
config
|
||||
)
|
||||
self.extension_manager.load_extension(ext_config.type, config)
|
||||
|
||||
def _create_app(self) -> None:
|
||||
routes = [
|
||||
Route("/health", self._health_check, methods=["GET"]),
|
||||
Route("/metrics", self._metrics, methods=["GET"]),
|
||||
Route(
|
||||
"/{path:path}",
|
||||
self._catch_all,
|
||||
methods=[
|
||||
"GET",
|
||||
"POST",
|
||||
"PUT",
|
||||
"DELETE",
|
||||
"PATCH",
|
||||
"OPTIONS"
|
||||
]
|
||||
),
|
||||
Route("/{path:path}", self._catch_all, methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]),
|
||||
]
|
||||
|
||||
self.app = Starlette(routes=routes)
|
||||
@@ -178,19 +152,16 @@ class PyServeServer:
|
||||
metrics = {}
|
||||
|
||||
for extension in self.extension_manager.extensions:
|
||||
if hasattr(extension, 'get_metrics'):
|
||||
if hasattr(extension, "get_metrics"):
|
||||
try:
|
||||
ext_metrics = getattr(extension, 'get_metrics')()
|
||||
ext_metrics = getattr(extension, "get_metrics")()
|
||||
metrics.update(ext_metrics)
|
||||
except Exception as e:
|
||||
logger.error("Error getting metrics from extension",
|
||||
extension=type(extension).__name__, error=str(e))
|
||||
logger.error("Error getting metrics from extension", extension=type(extension).__name__, error=str(e))
|
||||
|
||||
import json
|
||||
return Response(
|
||||
json.dumps(metrics, ensure_ascii=False, indent=2),
|
||||
media_type="application/json"
|
||||
)
|
||||
|
||||
return Response(json.dumps(metrics, ensure_ascii=False, indent=2), media_type="application/json")
|
||||
|
||||
async def _catch_all(self, request: Request) -> Response:
|
||||
return PlainTextResponse("404 Not Found", status_code=404)
|
||||
@@ -209,10 +180,7 @@ class PyServeServer:
|
||||
|
||||
try:
|
||||
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
||||
context.load_cert_chain(
|
||||
self.config.ssl.cert_file,
|
||||
self.config.ssl.key_file
|
||||
)
|
||||
context.load_cert_chain(self.config.ssl.cert_file, self.config.ssl.key_file)
|
||||
logger.info("SSL context created successfully")
|
||||
return context
|
||||
except Exception as e:
|
||||
@@ -237,20 +205,17 @@ class PyServeServer:
|
||||
}
|
||||
|
||||
if ssl_context:
|
||||
uvicorn_config.update({
|
||||
"ssl_keyfile": self.config.ssl.key_file,
|
||||
"ssl_certfile": self.config.ssl.cert_file,
|
||||
})
|
||||
uvicorn_config.update(
|
||||
{
|
||||
"ssl_keyfile": self.config.ssl.key_file,
|
||||
"ssl_certfile": self.config.ssl.cert_file,
|
||||
}
|
||||
)
|
||||
protocol = "https"
|
||||
else:
|
||||
protocol = "http"
|
||||
|
||||
logger.info(
|
||||
"Starting PyServe server",
|
||||
protocol=protocol,
|
||||
host=self.config.server.host,
|
||||
port=self.config.server.port
|
||||
)
|
||||
logger.info("Starting PyServe server", protocol=protocol, host=self.config.server.host, port=self.config.server.port)
|
||||
|
||||
try:
|
||||
assert self.app is not None, "App not initialized"
|
||||
@@ -306,6 +271,7 @@ class PyServeServer:
|
||||
self.extension_manager.cleanup()
|
||||
|
||||
from .logging_utils import shutdown_logging
|
||||
|
||||
shutdown_logging()
|
||||
|
||||
logger.info("Server stopped")
|
||||
@@ -317,13 +283,12 @@ class PyServeServer:
|
||||
metrics = {"server_status": "running"}
|
||||
|
||||
for extension in self.extension_manager.extensions:
|
||||
if hasattr(extension, 'get_metrics'):
|
||||
if hasattr(extension, "get_metrics"):
|
||||
try:
|
||||
ext_metrics = getattr(extension, 'get_metrics')()
|
||||
ext_metrics = getattr(extension, "get_metrics")()
|
||||
metrics.update(ext_metrics)
|
||||
except Exception as e:
|
||||
logger.error("Error getting metrics from extension",
|
||||
extension=type(extension).__name__, error=str(e))
|
||||
logger.error("Error getting metrics from extension", extension=type(extension).__name__, error=str(e))
|
||||
|
||||
return metrics
|
||||
|
||||
|
||||
Reference in New Issue
Block a user