df99305dd6
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 29s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 29s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 49s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 1m39s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 1m44s
CI/CD Pipeline / Validate - Style (pull_request) Successful in 2m19s
AI Code Review / AI Code Review (pull_request) Failing after 2m52s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m54s
CI/CD Pipeline / Validate - Security (pull_request) Successful in 4m11s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 6m23s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Failing after 1s
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 3m39s
问题:素材转码与视频生成共用 celery 默认队列、worker 单进程消费, 20+ 转码积压会把用户生成任务堵 40 分钟以上;孤儿清理把任务标 failed 后 Redis 队列消息未作废,消息被重投导致 failed→running 非法转换, worker 打印 ERROR 后继续产出半成品。 队列隔离: - 新增 packages/shared/celery_queues.py:generation/transcode/celery 三队列与 task_routes(generate_video→generation;ingest_asset/ classify_asset/duplication→transcode),apply_queue_settings() - worker 入口改双进程:generation worker 独占队列并内嵌 beat (prefetch=1, GENERATION_CONCURRENCY 默认 2),transcode worker 消费 transcode,celery(并发=总-2,最小 1),任一退出则整体终止 - compose/部署脚本/ps1 同步新增 GENERATION_CONCURRENCY 与健康检查 消息作废: - 新增 packages/shared/celery_orphan_guard.py:终态守卫 ensure_task_claimable、Redis 队列消息物理清理(JSON 信封解析, 按业务 id + celery headers.id 双匹配,未命中 rpush 保序)、 revoke_and_purge(control.revoke + 物理清队列双保险) - 入队点(生成/上传/分片/重试)send_task 后持久化 celery_task_id 到 generation_tasks/ingest_jobs(新列,067 迁移,失败仅 warning) - generate_video/ingest_asset 执行前校验 DB 状态:终态直接 discarded 不进业务逻辑;mark_processing 返回 False(非法转换)安全中止 - 孤儿/超时清理标 failed 时同时 revoke + 清队列消息 - pending 超时阈值 15→45 分钟,与 running 孤儿(20min)区分 测试:新增 22 个单测(路由表/真实 Redis 消息清理/终态守卫/ 非法转换中止/标 failed 后消息不重投/入队持久化),全量 14301 passed;067 迁移隔离 DDL 验证 upgrade/downgrade 通过。
59 lines
2.5 KiB
Python
59 lines
2.5 KiB
Python
"""Celery 队列定义与路由配置(API / Worker 共享)。
|
||
|
||
#1714 队列隔离:用户等待的视频生成任务路由到高优先级 `generation` 队列,
|
||
由专用 worker 进程独占消费;素材入库/转码等后台批量任务路由到 `transcode`
|
||
队列;其余杂项任务走默认 `celery` 队列。转码队列积压时,视频生成任务
|
||
仍能被 generation worker 立即领取执行,不会排队。
|
||
|
||
队列说明:
|
||
- generation: 用户提交的视频生成/预览渲染(延迟敏感,资源消耗大)
|
||
- transcode: 素材入库(HEVC 转码)、AI 分类、素材查重(批量、可排队)
|
||
- celery(默认): 配音、语音、下载缩略图、定时清理等杂项
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from kombu import Queue
|
||
|
||
# ── 队列名常量(生产端与消费端共用,禁止拼写漂移) ──
|
||
QUEUE_GENERATION = "generation"
|
||
QUEUE_TRANSCODE = "transcode"
|
||
QUEUE_DEFAULT = "celery"
|
||
|
||
# Worker 消费的队列列表(顺序即优先级:高优队列排在前面)
|
||
WORKER_QUEUES = (QUEUE_GENERATION, QUEUE_TRANSCODE, QUEUE_DEFAULT)
|
||
|
||
# 队列声明:持久化队列,broker 重启不丢消息
|
||
task_queues = (
|
||
Queue(QUEUE_GENERATION, routing_key=QUEUE_GENERATION, durable=True),
|
||
Queue(QUEUE_TRANSCODE, routing_key=QUEUE_TRANSCODE, durable=True),
|
||
Queue(QUEUE_DEFAULT, routing_key=QUEUE_DEFAULT, durable=True),
|
||
)
|
||
|
||
# ── 任务路由表:task name → 队列 ──
|
||
# 键支持 celery 标准通配符。
|
||
task_routes = {
|
||
# 高优先级:用户等待的视频生成
|
||
"worker.generate_video": {"queue": QUEUE_GENERATION},
|
||
# 后台批量:素材入库/转码 + AI 分类 + 素材查重,积压不影响生成
|
||
"worker.ingest_asset": {"queue": QUEUE_TRANSCODE},
|
||
"worker.classify_asset": {"queue": QUEUE_TRANSCODE},
|
||
"worker.process_duplication_check": {"queue": QUEUE_TRANSCODE},
|
||
"worker.check_duplicate": {"queue": QUEUE_TRANSCODE},
|
||
}
|
||
|
||
# 生成任务的预取数:渲染是长任务,预取 1 避免任务被某个 worker 占住不调度
|
||
GENERATION_WORKER_PREFETCH_MULTIPLIER = 1
|
||
|
||
|
||
def apply_queue_settings(app) -> None:
|
||
"""把队列隔离配置应用到 Celery app(API 生产端与 Worker 消费端都要调用)。
|
||
|
||
配置 task_queues / task_routes / task_default_queue。生产端靠 task_routes
|
||
把消息投递到对应队列;消费端靠 task_queues 声明自己消费哪些队列
|
||
(实际消费集由启动参数 -Q 控制)。
|
||
"""
|
||
app.conf.task_queues = task_queues
|
||
app.conf.task_routes = task_routes
|
||
app.conf.task_default_queue = QUEUE_DEFAULT
|