|
2 | 2 | from pathlib import Path |
3 | 3 |
|
4 | 4 | import asyncpg |
5 | | - |
6 | | -# from apscheduler import AsyncScheduler |
7 | | -# from apscheduler.datastores.sqlalchemy import SQLAlchemyDataStore |
8 | | -# from apscheduler.eventbrokers.redis import RedisEventBroker |
9 | 5 | from fastapi import Depends, FastAPI, Request |
10 | 6 | from fastapi.responses import HTMLResponse |
11 | 7 | from fastapi.templating import Jinja2Templates |
|
17 | 13 | from app.api.stuff import router as stuff_router |
18 | 14 | from app.api.user import router as user_router |
19 | 15 | from app.config import settings as global_settings |
20 | | - |
21 | | -# from app.database import engine |
22 | 16 | from app.redis import get_redis |
23 | 17 | from app.services.auth import AuthBearer |
| 18 | +from app.utils.logging import AppStructLogger |
24 | 19 |
|
25 | | -# from app.services.scheduler import SchedulerMiddleware |
26 | | -from app.utils.logging import AppLogger |
27 | | - |
28 | | -logger = AppLogger().get_logger() |
29 | | - |
| 20 | +logger = AppStructLogger().get_logger() |
30 | 21 | templates = Jinja2Templates(directory=Path(__file__).parent.parent / "templates") |
31 | 22 |
|
32 | | - |
33 | 23 | @asynccontextmanager |
34 | | -async def lifespan(_app: FastAPI): |
35 | | - # Load the redis connection |
36 | | - _app.redis = await get_redis() |
37 | | - |
38 | | - _postgres_dsn = global_settings.postgres_url.unicode_string() |
39 | | - |
| 24 | +async def lifespan(app: FastAPI): |
| 25 | + app.redis = await get_redis() |
| 26 | + postgres_dsn = global_settings.postgres_url.unicode_string() |
40 | 27 | try: |
41 | | - # TODO: cache with the redis connection |
42 | | - # Initialize the postgres connection pool |
43 | | - _app.postgres_pool = await asyncpg.create_pool( |
44 | | - dsn=_postgres_dsn, |
| 28 | + app.postgres_pool = await asyncpg.create_pool( |
| 29 | + dsn=postgres_dsn, |
45 | 30 | min_size=5, |
46 | 31 | max_size=20, |
47 | 32 | ) |
48 | | - logger.info(f"Postgres pool created: {_app.postgres_pool.get_idle_size()=}") |
| 33 | + logger.info("Postgres pool created", idle_size=app.postgres_pool.get_idle_size()) |
49 | 34 | yield |
50 | 35 | finally: |
51 | | - # close redis connection and release the resources |
52 | | - await _app.redis.close() |
53 | | - # close postgres connection pool and release the resources |
54 | | - await _app.postgres_pool.close() |
55 | | - |
56 | | - |
57 | | -app = FastAPI(title="Stuff And Nonsense API", version="0.19.0", lifespan=lifespan) |
58 | | - |
59 | | -app.include_router(stuff_router) |
60 | | -app.include_router(nonsense_router) |
61 | | -app.include_router(shakespeare_router) |
62 | | -app.include_router(user_router) |
63 | | -app.include_router(ml_router, prefix="/v1/ml", tags=["ML"]) |
64 | | - |
65 | | - |
66 | | -app.include_router(health_router, prefix="/v1/public/health", tags=["Health, Public"]) |
67 | | -app.include_router( |
68 | | - health_router, |
69 | | - prefix="/v1/health", |
70 | | - tags=["Health, Bearer"], |
71 | | - dependencies=[Depends(AuthBearer())], |
72 | | -) |
73 | | - |
74 | | - |
75 | | -@app.get("/index", response_class=HTMLResponse) |
76 | | -def get_index(request: Request): |
77 | | - return templates.TemplateResponse("index.html", {"request": request}) |
78 | | - |
79 | | - |
| 36 | + await app.redis.close() |
| 37 | + await app.postgres_pool.close() |
| 38 | + |
| 39 | +def create_app() -> FastAPI: |
| 40 | + app = FastAPI( |
| 41 | + title="Stuff And Nonsense API", |
| 42 | + version="0.19.0", |
| 43 | + lifespan=lifespan, |
| 44 | + ) |
| 45 | + app.include_router(stuff_router) |
| 46 | + app.include_router(nonsense_router) |
| 47 | + app.include_router(shakespeare_router) |
| 48 | + app.include_router(user_router) |
| 49 | + app.include_router(ml_router, prefix="/v1/ml", tags=["ML"]) |
| 50 | + app.include_router(health_router, prefix="/v1/public/health", tags=["Health, Public"]) |
| 51 | + app.include_router( |
| 52 | + health_router, |
| 53 | + prefix="/v1/health", |
| 54 | + tags=["Health, Bearer"], |
| 55 | + dependencies=[Depends(AuthBearer())], |
| 56 | + ) |
| 57 | + |
| 58 | + @app.get("/index", response_class=HTMLResponse) |
| 59 | + def get_index(request: Request): |
| 60 | + return templates.TemplateResponse("index.html", {"request": request}) |
| 61 | + |
| 62 | + return app |
| 63 | + |
| 64 | +app = create_app() |
| 65 | + |
| 66 | +# --- Unused/experimental code and TODOs --- |
| 67 | +# from apscheduler import AsyncScheduler |
| 68 | +# from apscheduler.datastores.sqlalchemy import SQLAlchemyDataStore |
| 69 | +# from apscheduler.eventbrokers.redis import RedisEventBroker |
| 70 | +# from app.database import engine |
| 71 | +# from app.services.scheduler import SchedulerMiddleware |
80 | 72 | # _scheduler_data_store = SQLAlchemyDataStore(engine, schema="scheduler") |
81 | | -# _scheduler_event_broker = RedisEventBroker( |
82 | | -# client_or_url=global_settings.redis_url.unicode_string() |
83 | | -# ) |
| 73 | +# _scheduler_event_broker = RedisEventBroker(client_or_url=global_settings.redis_url.unicode_string()) |
84 | 74 | # _scheduler_himself = AsyncScheduler(_scheduler_data_store, _scheduler_event_broker) |
85 | | -# |
86 | 75 | # app.add_middleware(SchedulerMiddleware, scheduler=_scheduler_himself) |
87 | | - |
88 | | - |
89 | | -# TODO: every not GET meth should reset cache |
90 | | -# TODO: every scheduler task which needs to act on database should have access to connection pool via request - maybe ? |
| 76 | +# TODO: every non-GET method should reset cache |
| 77 | +# TODO: scheduler tasks needing DB should access connection pool via request |
91 | 78 | # TODO: https://stackoverflow.com/questions/16053364/make-sure-only-one-worker-launches-the-apscheduler-event-in-a-pyramid-web-app-ru |
0 commit comments