""" app/workers/celery_app.py — Celery 任务框架壳 铁律:只传 task_id,绝不传 key(基石B)。 worker 内查库 → Fernet 解密 → 局部变量,不落盘不打日志。 """ import logging from celery import Celery from app.core.config import get_settings logger = logging.getLogger(__name__) settings = get_settings() celery_app = Celery( "clover", broker=settings.celery_broker(), backend=settings.celery_backend(), include=["app.workers.tasks", "app.workers.replenish_task"], ) celery_app.conf.update( task_serializer="json", result_serializer="json", accept_content=["json"], timezone="Asia/Shanghai", enable_utc=True, task_track_started=True, task_acks_late=True, # 任务处理完才 ACK,防丢失 worker_prefetch_multiplier=1, # 一次只取1条,防长任务堆积 # 🔴 visibility_timeout 必须 > 单任务最长耗时。生图(gpt-image-2)单张可达 270s+, # 整条流水线(多图+评图重试)可能十几分钟。默认仅 1h 时,长任务超时会被 Redis broker # 误判丢失而重新投递给另一 worker → 同一 task 被反复重跑、重复烧钱(task75 教训)。 # 设 2h 留足余量;配合 pipeline 入口幂等检查双保险。 broker_transport_options={"visibility_timeout": 7200}, task_routes={ "app.workers.tasks.run_generation_pipeline": {"queue": "generation"}, "app.workers.tasks.build_delivery_package": {"queue": "packaging"}, }, )