Files
xiaoxia-saas/apps/worker/worker_app/celery_app.py
T
saas-backend-agent fec656941d
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 6s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 24s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 24s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 1m41s
CI/CD Pipeline / Unit Tests (pull_request) Successful in 1m57s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 1m57s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m44s
CI/CD Pipeline / Validate - Style (pull_request) Failing after 2m50s
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 241h52m35s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 241h52m38s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 241h52m43s
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Failing after 241h52m49s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Failing after 241h52m49s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 241h53m9s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 241h53m9s
CI/CD Pipeline / PR Build Web Image (pull_request) Failing after 241h53m15s
CI/CD Pipeline / Check push changed paths (pull_request) Failing after 241h53m26s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Failing after 241h53m16s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 242h27m12s
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Failing after 242h27m25s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 242h27m45s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 242h27m52s
fix(#1714): 同名兜底去重误杀新视频 + ingest 链路孤儿清理/启动恢复
根因(staging 实证 IMG_2285.MOV file_size=0 卡 processing 持续误杀):
direct complete 不传 file_size,find_recent_active_by_library_and_name
的大小校验 if file_size>0 不生效,30 分钟内同名视频(iPhone IMG_xxxx.MOV)
即使内容全新也被同名兜底误判重复跳过。

兜底去重收紧(宁可漏判不可误杀):
- _find_duplicate_asset:file_hash/client_upload_id 非空时不走同名兜底
  (hash 已代表内容);走到兜底必须 file_size>0 且与记录大小严格一致
- find_recent_active_by_library_and_name:file_size=0 直接返回 None,
  大小条件改为 SQL 内严格等值匹配
- complete 的 _create_pending_asset 补传 file_size(之前占位记录大小永远 0)

ingest 链路孤儿兜底(此前只有 generation 链路有清理):
- 新增 packages/application/ingest_orphan_cleanup.py:
  - processing>60min / pending>90min 的 ingest_job 标 failed,关联
    processing/uploading asset 联动标 error;无 job 关联超 120min 孤儿
    占位 asset 也标 error(beat 每 10 分钟巡检)
  - worker 启动恢复:processing 超 10 分钟的 job CAS 重置 pending 并
    重新派单(Redis SET NX 锁互斥双 worker,旧消息重投由执行前守卫丢弃)
- celery 配置:task_reject_on_worker_lost=True;
  broker visibility_timeout=4h(acks_late 下长转码任务不被误重投)

单测:同名不同大小放行 / hash 非空不走兜底 / file_size=0 放行 /
同名同大小 processing 才判重;孤儿清理 9 例、启动恢复 4 例、
仓储严格守卫 6 例、beat 串联 2 例。diff coverage 100%。

前端配合(前端工程师):completeDirectUpload 请求体补 file_size=file.size。
2026-09-06 13:29:59 +08:00

65 lines
3.0 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from celery import Celery
from worker_app.core.config import get_settings
settings = get_settings()
celery_app = Celery(settings.worker_name)
celery_app.conf.broker_url = settings.broker_url
celery_app.conf.result_backend = settings.result_backend
celery_app.conf.broker_connection_retry_on_startup = True
# #1714 队列隔离:generation(高优,独占 worker)/ transcode(素材转码)/ celery(默认)
from packages.shared.celery_queues import ( # noqa: E402
GENERATION_WORKER_PREFETCH_MULTIPLIER,
apply_queue_settings,
)
apply_queue_settings(celery_app)
# 长渲染任务预取 1,避免任务被预取占住导致调度不均
celery_app.conf.worker_prefetch_multiplier = GENERATION_WORKER_PREFETCH_MULTIPLIER
celery_app.conf.task_acks_late = True # worker 崩溃时未完成任务重回队列,由执行前守卫丢弃作废消息
# worker 进程被 OOM/容器硬杀时拒绝 ack,消息留在队列由其他 worker 接手
celery_app.conf.task_reject_on_worker_lost = True
# Redis broker 消息可见性超时(#1714):acks_late 下,消息被预取后 visibility_timeout
# 内未 ack 才会重投。长任务(ingest HEVC 转码 20-30 分钟、生成硬超时 11 分钟)
# 必须远大于最长执行时间,否则正常任务会在执行中被误重投;4 小时覆盖最长转码 + 余量。
celery_app.conf.broker_transport_options = {"visibility_timeout": 4 * 60 * 60}
celery_app.conf.imports = (
"worker_app.tasks.health",
"worker_app.tasks.ingest",
"worker_app.tasks.classification",
"worker_app.tasks.generation",
"worker_app.tasks.voice_extraction",
"worker_app.tasks.voice_clone",
"worker_app.tasks.tts_synthesis",
"worker_app.tasks.batch_download",
"worker_app.tasks.duplication_check",
"worker_app.tasks._startup",
"apps.worker.video_processing.dedup",
"worker_app.tasks.cleanup",
)
# Celery Beat 定时任务调度
# 注:worker 单实例内嵌 beat(entrypoint-worker.sh -B),定时任务不会重复执行
celery_app.conf.beat_schedule = {
# pending 任务超时清理:worker 停止消费后,卡 pending 的任务 15 分钟内释放限流名额
"cleanup-stale-pending-tasks": {
"task": "worker.cleanup_stale_pending_tasks",
"schedule": 300.0, # 每 5 分钟(秒)
"options": {"expires": 240}, # 4 分钟过期,避免堆积
},
# running 孤儿任务巡检:容器重启/进程被杀后卡 running 的任务,20 分钟无更新则判失败
"cleanup-stale-running-tasks": {
"task": "worker.cleanup_stale_running_tasks",
"schedule": 300.0, # 每 5 分钟(秒)
"options": {"expires": 240},
},
# 上传/转码链路孤儿巡检:worker 重启丢 prefetch 消息后,卡 pending/processing
# 的 ingest_job + asset 占位超时标终态(#1714)。转码任务较长,10 分钟一轮
"cleanup-stale-ingest-jobs": {
"task": "worker.cleanup_stale_ingest_jobs",
"schedule": 600.0, # 每 10 分钟(秒)
"options": {"expires": 540},
},
}