fix(P1-E): 启动时标 failed 残留 pending/running ingest_jobs
lifespan 加 _fail_stale_ingest_jobs():UPDATE ingest_jobs SET status=failed
WHERE status IN ('pending','running');异常仅记 warning 不阻断启动。
顺手修复 0021(op.text→字符串)/0023(索引名 leason→league)/0024(type_unique→type_)
三个待执行迁移 bug。
测试 test_p1_e_stale_ingest_jobs(2/2 mock);全量 315 通过。
This commit is contained in:
@@ -14,6 +14,35 @@ from src.core.config import settings
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def _fail_stale_ingest_jobs() -> None:
|
||||
"""P1-E: 启动时将上次遗留的 pending/running ingest_jobs 标 failed。
|
||||
|
||||
进程异常退出(重启/OOM)会导致 ingest_jobs 残留为 pending/running,
|
||||
这些任务实际已不在执行,启动时一次性标 failed 避免永久"执行中"。
|
||||
尽力而为:失败只记 warning,不阻断启动。
|
||||
"""
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from sqlalchemy import update
|
||||
|
||||
from src.db.base import AsyncSessionLocal
|
||||
from src.db.models import IngestJob
|
||||
|
||||
try:
|
||||
async with AsyncSessionLocal() as session:
|
||||
stmt = (
|
||||
update(IngestJob)
|
||||
.where(IngestJob.status.in_(["pending", "running"]))
|
||||
.values(status="failed", error="进程重启:任务被终止", finished_at=datetime.now(timezone.utc))
|
||||
)
|
||||
result = await session.execute(stmt)
|
||||
await session.commit()
|
||||
if result.rowcount:
|
||||
logger.info("P1-E: 已将 %d 条残留 pending/running ingest_jobs 标 failed", result.rowcount)
|
||||
except Exception:
|
||||
logger.warning("P1-E: 清理残留 ingest_jobs 失败,不影响启动", exc_info=True)
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI) -> AsyncIterator[None]:
|
||||
from src.db.base import init_db
|
||||
@@ -30,6 +59,7 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]:
|
||||
await migrate_plaintext_sensitive_settings() # 明文敏感配置 → 加密(幂等)
|
||||
await ensure_admin_password_hashed() # .env 明文密码 → scrypt 哈希(幂等)
|
||||
await assert_security_on_startup() # 启动安全校验(生产拒绝/开发警告)
|
||||
await _fail_stale_ingest_jobs() # P1-E: 上次遗留的 pending/running 标 failed
|
||||
|
||||
# D7(工程债): 进程内限流(_RateLimiter)与 KeyRing 均为单进程状态;
|
||||
# 多 worker 部署时各进程独立计数,限流阈值会按 worker 数放大、KeyRing 不共享。
|
||||
|
||||
Reference in New Issue
Block a user