refactor: extract admin business logic to services, introduce job queue, add derived index helpers
- Move DB operations from routes/admin.py to services/admin.py (get_logs_context, query_summary_statuses, retry_failed, delete/reset operations) - Add services/jobs.py with Job/JobEvent-based async job queue (create_job, run_job, enqueue_job) - Add services/derived.py with FTS5 reindex and paper index deletion helpers - Refactor scheduler to use job queue instead of direct pipeline calls - Add heartbeat_at/expires_at to TaskLock for lock health tracking - Remove DESIGN_REVIEW.md - Update tests: remove redundant integration tests, add unit tests for new services
This commit is contained in:
@@ -32,6 +32,26 @@ class SummaryState(StrEnum):
|
||||
PERMANENT_FAILURE = "permanent_failure"
|
||||
|
||||
|
||||
class JobStatus(StrEnum):
|
||||
"""后台任务状态枚举 — 对应 jobs.status 列。"""
|
||||
|
||||
QUEUED = "queued"
|
||||
RUNNING = "running"
|
||||
SUCCESS = "success"
|
||||
FAILED = "failed"
|
||||
STALE = "stale"
|
||||
CANCELLED = "cancelled"
|
||||
|
||||
|
||||
class JobEventStatus(StrEnum):
|
||||
"""任务阶段事件状态枚举 — 对应 job_events.status 列。"""
|
||||
|
||||
STARTED = "started"
|
||||
SUCCESS = "success"
|
||||
FAILED = "failed"
|
||||
INFO = "info"
|
||||
|
||||
|
||||
# ── papers ──────────────────────────────────────────────────────────────
|
||||
class Paper(Base):
|
||||
__tablename__ = "papers"
|
||||
@@ -194,9 +214,48 @@ class TaskLock(Base):
|
||||
status = Column(String, nullable=False)
|
||||
owner = Column(String)
|
||||
acquired_at = Column(DateTime, nullable=False)
|
||||
heartbeat_at = Column(DateTime)
|
||||
expires_at = Column(DateTime)
|
||||
released_at = Column(DateTime)
|
||||
|
||||
|
||||
# ── jobs / job_events ──────────────────────────────────────────────────
|
||||
class Job(Base):
|
||||
__tablename__ = "jobs"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
type = Column(String, nullable=False, index=True)
|
||||
status = Column(String, nullable=False, default=JobStatus.QUEUED, index=True)
|
||||
owner = Column(String)
|
||||
payload_json = Column(Text)
|
||||
result_json = Column(Text)
|
||||
error = Column(Text)
|
||||
created_at = Column(DateTime, nullable=False)
|
||||
started_at = Column(DateTime)
|
||||
heartbeat_at = Column(DateTime)
|
||||
completed_at = Column(DateTime)
|
||||
|
||||
events = relationship(
|
||||
"JobEvent", back_populates="job", cascade="all, delete-orphan"
|
||||
)
|
||||
|
||||
|
||||
class JobEvent(Base):
|
||||
__tablename__ = "job_events"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
job_id = Column(
|
||||
Integer, ForeignKey("jobs.id", ondelete="CASCADE"), nullable=False, index=True
|
||||
)
|
||||
stage = Column(String, nullable=False)
|
||||
status = Column(String, nullable=False)
|
||||
message = Column(Text)
|
||||
payload_json = Column(Text)
|
||||
created_at = Column(DateTime, nullable=False)
|
||||
|
||||
job = relationship("Job", back_populates="events")
|
||||
|
||||
|
||||
# ── user data ──────────────────────────────────────────────────────────
|
||||
class UserBookmark(Base):
|
||||
__tablename__ = "user_bookmarks"
|
||||
|
||||
Reference in New Issue
Block a user