1515import json
1616import logging
1717import os
18- from datetime import datetime
18+ from contextlib import asynccontextmanager
19+ from datetime import datetime , timezone
1920from pathlib import Path
2021from typing import Any
2122
@@ -157,7 +158,8 @@ async def notification_listener(stop_event: asyncio.Event) -> None:
157158 """Listen for ``pg_notify`` events until the app shuts down."""
158159
159160 loop = asyncio .get_running_loop ()
160- conn = await asyncpg .connect (dsn = app .state .database_dsn )
161+ database_dsn = build_database_dsn ()
162+ conn = await asyncpg .connect (dsn = database_dsn )
161163
162164 def _listener (_connection : asyncpg .Connection , _pid : int , _channel : str , payload : str ) -> None :
163165 loop .create_task (forward_notification (payload ))
@@ -170,34 +172,22 @@ def _listener(_connection: asyncpg.Connection, _pid: int, _channel: str, payload
170172 await conn .close ()
171173
172174
173- app = FastAPI (title = "FastAPI Postgres Pub/Sub Chat" )
174- app .state .connections = WebSocketRegistry ()
175- app .state .listener_stop : asyncio .Event | None = None
176- app .state .listener_task : asyncio .Task | None = None
177- app .state .db_pool : asyncpg .Pool | None = None
178- app .state .database_dsn = build_database_dsn ()
179-
180-
181- def get_pool () -> asyncpg .Pool :
182- pool = app .state .db_pool
183- if pool is None :
184- raise HTTPException (status_code = 500 , detail = "Database connection not ready" )
185- return pool
186-
187-
188- @app .on_event ("startup" )
189- async def startup () -> None :
190- pool = await asyncpg .create_pool (dsn = app .state .database_dsn , min_size = 1 , max_size = 5 )
175+ @asynccontextmanager
176+ async def lifespan (app : FastAPI ):
177+ """Manage application lifespan events."""
178+ # Startup
179+ database_dsn = build_database_dsn ()
180+ pool = await asyncpg .create_pool (dsn = database_dsn , min_size = 1 , max_size = 5 )
191181 app .state .db_pool = pool
192182 await create_tables (pool )
193183
194184 stop_event = asyncio .Event ()
195185 app .state .listener_stop = stop_event
196186 app .state .listener_task = asyncio .create_task (notification_listener (stop_event ))
197-
198-
199- @ app . on_event ( "shutdown" )
200- async def shutdown () -> None :
187+
188+ yield
189+
190+ # Shutdown
201191 stop_event = app .state .listener_stop
202192 if stop_event :
203193 stop_event .set ()
@@ -210,6 +200,22 @@ async def shutdown() -> None:
210200 await pool .close ()
211201
212202
203+ app = FastAPI (title = "FastAPI Postgres Pub/Sub Chat" , lifespan = lifespan )
204+ app .state .connections = WebSocketRegistry ()
205+ app .state .listener_stop : asyncio .Event | None = None
206+ app .state .listener_task : asyncio .Task | None = None
207+ app .state .db_pool : asyncpg .Pool | None = None
208+
209+
210+ def get_pool () -> asyncpg .Pool :
211+ pool = app .state .db_pool
212+ if pool is None :
213+ raise HTTPException (status_code = 500 , detail = "Database connection not ready" )
214+ return pool
215+
216+
217+
218+
213219@app .get ("/" , response_class = HTMLResponse )
214220async def index () -> HTMLResponse :
215221 if not TEMPLATE_PATH .exists ():
@@ -247,4 +253,4 @@ async def healthcheck() -> dict[str, str]:
247253 pool = get_pool ()
248254 async with pool .acquire () as conn :
249255 await conn .execute ("SELECT 1" )
250- return {"status" : "ok" , "timestamp" : datetime .utcnow ( ).isoformat ()}
256+ return {"status" : "ok" , "timestamp" : datetime .now ( timezone . utc ).isoformat ()}
0 commit comments