X-Git-Url: https://git.openstreetmap.org./nominatim.git/blobdiff_plain/996026e5ed9f1f07e618b67de9077c3e338c0302..78c19bc006d5957f183968d086226be4b2b65fe3:/nominatim/server/starlette/server.py?ds=inline diff --git a/nominatim/server/starlette/server.py b/nominatim/server/starlette/server.py index 5567ac9c..c9828991 100644 --- a/nominatim/server/starlette/server.py +++ b/nominatim/server/starlette/server.py @@ -7,14 +7,15 @@ """ Server implementation using the starlette webserver framework. """ -from typing import Any, Optional, Mapping, Callable, cast, Coroutine +from typing import Any, Optional, Mapping, Callable, cast, Coroutine, Dict, Awaitable from pathlib import Path import datetime as dt +import asyncio from starlette.applications import Starlette from starlette.routing import Route from starlette.exceptions import HTTPException -from starlette.responses import Response +from starlette.responses import Response, PlainTextResponse, HTMLResponse from starlette.requests import Request from starlette.middleware import Middleware from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint @@ -22,6 +23,7 @@ from starlette.middleware.cors import CORSMiddleware from nominatim.api import NominatimAPIAsync import nominatim.api.v1 as api_impl +import nominatim.api.logging as loglib from nominatim.config import Configuration class ParamWrapper(api_impl.ASGIAdaptor): @@ -93,7 +95,7 @@ class FileLoggingMiddleware(BaseHTTPMiddleware): finish = dt.datetime.now(tz=dt.timezone.utc) - for endpoint in ('reverse', 'search', 'lookup'): + for endpoint in ('reverse', 'search', 'lookup', 'details'): if request.url.path.startswith('/' + endpoint): qtype = endpoint break @@ -110,6 +112,19 @@ class FileLoggingMiddleware(BaseHTTPMiddleware): return response +async def timeout_error(request: Request, #pylint: disable=unused-argument + _: Exception) -> Response: + """ Error handler for query timeouts. + """ + loglib.log().comment('Aborted: Query took too long to process.') + logdata = loglib.get_and_disable() + + if logdata: + return HTMLResponse(logdata) + + return PlainTextResponse("Query took too long to process.", status_code=503) + + def get_application(project_dir: Path, environ: Optional[Mapping[str, str]] = None, debug: bool = True) -> Starlette: @@ -136,10 +151,16 @@ def get_application(project_dir: Path, if log_file: middleware.append(Middleware(FileLoggingMiddleware, file_name=log_file)) + exceptions: Dict[Any, Callable[[Request, Exception], Awaitable[Response]]] = { + TimeoutError: timeout_error, + asyncio.TimeoutError: timeout_error + } + async def _shutdown() -> None: await app.state.API.close() app = Starlette(debug=debug, routes=routes, middleware=middleware, + exception_handlers=exceptions, on_shutdown=[_shutdown]) app.state.API = NominatimAPIAsync(project_dir, environ)