Files
meme/main.py
konjacpotato c097d0b549
All checks were successful
Gitea Actions Demo / deploy (push) Successful in 20s
commit code
2025-12-29 20:34:35 +08:00

98 lines
2.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from datetime import datetime
from fastapi import FastAPI
from fastapi.concurrency import asynccontextmanager
from config.settings import settings
from scheduler import job_story_portal
from utils.logger import logger
from scheduler.scheduler import scheduler
import scheduler.jobs as jobs
from config.app import create_app
"""
启动方式:
python -m uvicorn main:app --reload
说明:
- 使用 FastAPI lifespan 管理 APScheduler 生命周期(替代已废弃的 on_event
- 避免 Uvicorn reload 模式下调度器重复启动
- 所有 Job 在应用启动时统一注册
"""
def _add_jobs():
"""
注册所有定时任务。
注意:
- 增加重复检查,避免 reload 或多进程导致重复添加。
- replace_existing=True 保证任务更新时无需手动删除。
"""
if not scheduler.get_job("heartbeat-job"):
scheduler.add_job(
jobs.job_heartbeat,
trigger="interval",
seconds=10,
id="heartbeat-job",
replace_existing=True,
)
logger.info("Job 'heartbeat-job' registered.")
else:
logger.info("Job 'heartbeat-job' already exists. Skipped.")
# 需要立即执行一次每日文章生成任务
scheduler.add_job(
job_story_portal.job_generate_daily_article,
trigger="interval",
seconds=86400, # 每天运行一次
id="generate-daily-article-job",
replace_existing=True,
next_run_time=datetime.now(datetime.timezone.utc), # 启动即执行一次
misfire_grace_time=60, # 允许错过一分钟内的执行
)
logger.info("Job 'generate-daily-article-job' registered.")
@asynccontextmanager
async def lifespan(app: FastAPI):
"""
FastAPI 应用生命周期管理。
startup:
- 注册定时任务
- 启动 APScheduler避免 reload 环境下重复启动)
shutdown:
- 安全关闭 APScheduler
yield:
- 让 FastAPI 在此期间正常运行
"""
logger.info("==== Lifespan: startup ====")
# 防止 Uvicorn reload 启动两个进程导致重复启动 scheduler
if scheduler.running:
logger.warning("Scheduler already running. Skip start.")
else:
try:
scheduler.start()
logger.info("APScheduler started.")
except Exception:
logger.exception("Failed to start APScheduler:")
raise
_add_jobs()
yield # ---- 应用运行中 ----
logger.info("==== Lifespan: shutdown ====")
# 仅在 scheduler 正常运行时关闭
if scheduler.running:
scheduler.shutdown(wait=False)
logger.info("APScheduler stopped.")
else:
logger.info("Scheduler was not running. Skip shutdown.")
# 创建 FastAPI 应用(注入 lifespan 管理逻辑)
app = create_app(lifespan=lifespan)