feat(scheduler): APScheduler 3 jobs météo dans FastAPI lifespan
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -21,7 +21,13 @@ async def lifespan(app: FastAPI):
|
||||
create_db_and_tables()
|
||||
from app.seed import run_seed
|
||||
run_seed()
|
||||
# Démarrer le scheduler météo
|
||||
from app.services.scheduler import setup_scheduler
|
||||
setup_scheduler()
|
||||
yield
|
||||
# Arrêter le scheduler
|
||||
from app.services.scheduler import scheduler
|
||||
scheduler.shutdown(wait=False)
|
||||
|
||||
|
||||
app = FastAPI(title="Jardin API", lifespan=lifespan)
|
||||
|
||||
108
backend/app/services/scheduler.py
Normal file
108
backend/app/services/scheduler.py
Normal file
@@ -0,0 +1,108 @@
|
||||
"""Scheduler APScheduler — 3 jobs de collecte météo."""
|
||||
import logging
|
||||
from datetime import datetime
|
||||
|
||||
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
scheduler = AsyncIOScheduler(timezone="Europe/Paris")
|
||||
|
||||
|
||||
def _store_station_current() -> None:
|
||||
"""Collecte et stocke les données actuelles de la station."""
|
||||
from app.services.station import fetch_current
|
||||
from app.models.meteo import MeteoStation
|
||||
from app.database import engine
|
||||
from sqlmodel import Session
|
||||
|
||||
data = fetch_current()
|
||||
if not data:
|
||||
logger.warning("Station current: aucune donnée collectée")
|
||||
return
|
||||
|
||||
now_str = datetime.now().strftime("%Y-%m-%dT%H:00")
|
||||
entry = MeteoStation(date_heure=now_str, type="current", **data)
|
||||
|
||||
with Session(engine) as session:
|
||||
existing = session.get(MeteoStation, now_str)
|
||||
if existing:
|
||||
for k, v in data.items():
|
||||
setattr(existing, k, v)
|
||||
session.add(existing)
|
||||
else:
|
||||
session.add(entry)
|
||||
session.commit()
|
||||
logger.info(f"Station current stockée : {now_str}")
|
||||
|
||||
|
||||
def _store_station_veille() -> None:
|
||||
"""Collecte et stocke le résumé de la veille (NOAA)."""
|
||||
from datetime import timedelta
|
||||
from app.services.station import fetch_yesterday_summary
|
||||
from app.models.meteo import MeteoStation
|
||||
from app.database import engine
|
||||
from sqlmodel import Session
|
||||
|
||||
data = fetch_yesterday_summary()
|
||||
if not data:
|
||||
logger.warning("Station veille: aucune donnée collectée")
|
||||
return
|
||||
|
||||
yesterday = (datetime.now() - timedelta(days=1)).strftime("%Y-%m-%dT00:00")
|
||||
entry = MeteoStation(date_heure=yesterday, type="veille", **data)
|
||||
|
||||
with Session(engine) as session:
|
||||
existing = session.get(MeteoStation, yesterday)
|
||||
if existing:
|
||||
for k, v in data.items():
|
||||
setattr(existing, k, v)
|
||||
session.add(existing)
|
||||
else:
|
||||
session.add(entry)
|
||||
session.commit()
|
||||
logger.info(f"Station veille stockée : {yesterday}")
|
||||
|
||||
|
||||
def _store_open_meteo() -> None:
|
||||
"""Collecte et stocke les prévisions Open-Meteo."""
|
||||
from app.services.meteo import fetch_and_store_forecast
|
||||
from app.models.meteo import MeteoOpenMeteo
|
||||
from app.database import engine
|
||||
from sqlmodel import Session
|
||||
|
||||
rows = fetch_and_store_forecast()
|
||||
if not rows:
|
||||
logger.warning("Open-Meteo: aucune donnée collectée")
|
||||
return
|
||||
|
||||
with Session(engine) as session:
|
||||
for row in rows:
|
||||
existing = session.get(MeteoOpenMeteo, row["date"])
|
||||
if existing:
|
||||
for k, v in row.items():
|
||||
if k != "date":
|
||||
setattr(existing, k, v)
|
||||
session.add(existing)
|
||||
else:
|
||||
session.add(MeteoOpenMeteo(**row))
|
||||
session.commit()
|
||||
logger.info(f"Open-Meteo stocké : {len(rows)} jours")
|
||||
|
||||
|
||||
def setup_scheduler() -> None:
|
||||
"""Configure et démarre le scheduler."""
|
||||
scheduler.add_job(
|
||||
_store_station_current, "interval", hours=1,
|
||||
next_run_time=datetime.now(), id="station_current", replace_existing=True,
|
||||
)
|
||||
scheduler.add_job(
|
||||
_store_station_veille, "cron", hour=6, minute=0,
|
||||
next_run_time=datetime.now(), id="station_veille", replace_existing=True,
|
||||
)
|
||||
scheduler.add_job(
|
||||
_store_open_meteo, "interval", hours=1,
|
||||
next_run_time=datetime.now(), id="open_meteo", replace_existing=True,
|
||||
)
|
||||
scheduler.start()
|
||||
logger.info("Scheduler météo démarré (3 jobs)")
|
||||
Reference in New Issue
Block a user