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 通过。
64 lines
2.3 KiB
Bash
Executable File
64 lines
2.3 KiB
Bash
Executable File
#!/bin/bash
|
||
# Worker 启动脚本 — #1714 队列隔离
|
||
#
|
||
# 部署约束:worker 容器单实例(replicas=1),容器内启动两个 celery 进程:
|
||
# 1. generation-worker:独占消费 generation 队列(用户视频生成,高优先级),
|
||
# 内嵌 celery beat(-B),定时清理任务只在一个进程里跑,避免重复执行;
|
||
# 2. transcode-worker:消费 transcode + celery 默认队列(素材转码/分类/查重/
|
||
# 配音/下载等后台任务)。
|
||
# 转码队列积压时,generation 队列仍有独立 worker 立即领取视频生成任务。
|
||
#
|
||
# 环境变量:
|
||
# WORKER_CONCURRENCY 总并发槽参考(默认 4);生成 worker 并发默认 2,
|
||
# 可用 GENERATION_CONCURRENCY 覆盖
|
||
# GENERATION_CONCURRENCY generation worker 并发(默认 2)
|
||
# TRANSCODE_CONCURRENCY transcode worker 并发(默认 = WORKER_CONCURRENCY - 2,最小 1)
|
||
# WORKER_MAX_TASKS_PER_CHILD 每个子进程最大任务数(默认 100)
|
||
|
||
set -e
|
||
|
||
CONCURRENCY="${WORKER_CONCURRENCY:-4}"
|
||
MAX_TASKS="${WORKER_MAX_TASKS_PER_CHILD:-100}"
|
||
|
||
GEN_CONCURRENCY="${GENERATION_CONCURRENCY:-2}"
|
||
if [ -z "$TRANSCODE_CONCURRENCY" ]; then
|
||
TRANS_CONCURRENCY=$((CONCURRENCY - GEN_CONCURRENCY))
|
||
if [ "$TRANS_CONCURRENCY" -lt 1 ]; then
|
||
TRANS_CONCURRENCY=1
|
||
fi
|
||
else
|
||
TRANS_CONCURRENCY="$TRANSCODE_CONCURRENCY"
|
||
fi
|
||
|
||
echo "Starting generation worker (queue=generation, concurrency=$GEN_CONCURRENCY, beat embedded)"
|
||
celery \
|
||
-A worker_app.celery_app \
|
||
worker \
|
||
--loglevel=info \
|
||
"-B" \
|
||
-Q generation \
|
||
"--concurrency=${GEN_CONCURRENCY}" \
|
||
"--max-tasks-per-child=${MAX_TASKS}" \
|
||
-n generation@%h &
|
||
GEN_PID=$!
|
||
|
||
echo "Starting transcode worker (queues=transcode,celery, concurrency=$TRANS_CONCURRENCY)"
|
||
celery \
|
||
-A worker_app.celery_app \
|
||
worker \
|
||
--loglevel=info \
|
||
-Q transcode,celery \
|
||
"--concurrency=${TRANS_CONCURRENCY}" \
|
||
"--max-tasks-per-child=${MAX_TASKS}" \
|
||
-n transcode@%h &
|
||
TRANS_PID=$!
|
||
|
||
# 任一进程退出则终止另一个,让容器整体重启(restart: unless-stopped)
|
||
trap 'echo "Shutting down workers..."; kill -TERM $GEN_PID $TRANS_PID 2>/dev/null || true' TERM INT
|
||
|
||
wait -n $GEN_PID $TRANS_PID
|
||
EXIT_CODE=$?
|
||
echo "One worker exited (code=$EXIT_CODE), stopping the other..."
|
||
kill -TERM $GEN_PID $TRANS_PID 2>/dev/null || true
|
||
exit $EXIT_CODE
|