"""新增 ingest_jobs 表 Revision ID: 0019_ingest_jobs Revises: 0018_match_checks Create Date: 2026-09-21 采集任务状态跟踪:POST /ingest/bzzoiro 创建 pending job 后台执行, 解决 fire-and-forget 不可观测问题(admin 可查询任务级状态与结果摘要)。 """ from typing import Sequence, Union from alembic import op import sqlalchemy as sa from sqlalchemy.dialects.postgresql import JSONB # revision identifiers, used by Alembic. revision: str = '0019_ingest_jobs' down_revision: Union[str, None] = '0018_match_checks' branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: op.create_table( 'ingest_jobs', sa.Column('id', sa.String(36), primary_key=True), sa.Column('task', sa.String(20), nullable=False), sa.Column('params', JSONB, nullable=False), sa.Column('status', sa.String(20), nullable=False, server_default='pending'), sa.Column('result', JSONB), sa.Column('error', sa.Text()), sa.Column('created_at', sa.DateTime(timezone=True)), sa.Column('started_at', sa.DateTime(timezone=True)), sa.Column('finished_at', sa.DateTime(timezone=True)), sa.CheckConstraint( "status IN ('pending','running','success','failed')", name='ck_ingest_jobs_status', ), ) op.create_index('ix_ingest_jobs_created', 'ingest_jobs', ['created_at']) def downgrade() -> None: op.drop_index('ix_ingest_jobs_created', table_name='ingest_jobs') op.drop_table('ingest_jobs')