"""分析任务队列:持久化到 SQLite,断电可恢复。""" from __future__ import annotations from datetime import datetime from enum import Enum from sqlalchemy import DateTime, ForeignKey, Index, Integer, String, Text, func from sqlalchemy.orm import Mapped, mapped_column from app.core.db import Base class JobKind(str, Enum): """任务种类。""" OCR = "ocr" VLM = "vlm" FULL = "full" # OCR + VLM 一条龙 class JobStatus(str, Enum): """任务运行状态。""" PENDING = "pending" RUNNING = "running" DONE = "done" FAILED = "failed" class Job(Base): """单条分析任务记录。""" __tablename__ = "jobs" __table_args__ = ( Index("ix_jobs_status", "status"), Index("ix_jobs_kind_status", "kind", "status"), ) id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) screenshot_id: Mapped[int] = mapped_column( Integer, ForeignKey("screenshots.id", ondelete="CASCADE"), nullable=False, ) kind: Mapped[str] = mapped_column(String(16), default=JobKind.FULL.value) status: Mapped[str] = mapped_column(String(16), default=JobStatus.PENDING.value) retries: Mapped[int] = mapped_column(Integer, default=0) last_error: Mapped[str | None] = mapped_column(Text, nullable=True) created_at: Mapped[datetime] = mapped_column( DateTime, server_default=func.now(), nullable=False ) started_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) finished_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)