"""Run the recipe web app with an explicit config path.""" from __future__ import annotations import logging import time from pathlib import Path import click import uvicorn from recipe_web.config import load_pipeline_config_with_db_url, load_web_app_config_from_path from recipe_web.observability import setup_observability logger = logging.getLogger(__name__) def run_server(config_path: Path) -> None: """Run the recipe web server with the given config path.""" startup_t0 = time.monotonic() web_config = load_web_app_config_from_path(config_path) pipeline_config = load_pipeline_config_with_db_url(web_config.db_url) logger.info("[startup] config loaded in %.2fs", time.monotonic() - startup_t0) t_otel = time.monotonic() setup_observability(web_config.observability, []) logger.info("[startup] observability setup in %.2fs", time.monotonic() - t_otel) t_import = time.monotonic() from recipe_web.app_factory import build_app, build_app_state logger.info("[startup] app_factory imported in %.2fs", time.monotonic() - t_import) t_state = time.monotonic() app_state = build_app_state(web_config, pipeline_config) logger.info("[startup] app_state built in %.2fs", time.monotonic() - t_state) t_app = time.monotonic() app = build_app(app_state, web_config) logger.info("[startup] app built in %.2fs", time.monotonic() - t_app) logger.info("[startup] total pre-uvicorn: %.2fs", time.monotonic() - startup_t0) uvicorn.run(app, host=web_config.server.host, port=web_config.server.port) @click.command() @click.option( "--config-path", type=click.Path(path_type=Path, exists=True, dir_okay=False), required=True, ) def main(config_path: Path) -> None: """CLI entrypoint for `scripts.run_webapp`.""" run_server(config_path) if __name__ == "__main__": main()