2026-08-31 18:01:34 +08:00
|
|
|
|
# services/task_dispatcher.py
|
|
|
|
|
|
"""后台处理任务分派器 - 统一 upload/batch 路由的 Celery/asyncio 分派逻辑。
|
|
|
|
|
|
|
|
|
|
|
|
修复两个问题:
|
|
|
|
|
|
1. fire-and-forget:asyncio.create_task 返回值未持有引用,任务可能被 GC 中途回收,
|
|
|
|
|
|
异常也无从浮现(python 官方文档明确警告的模式);
|
|
|
|
|
|
2. 复制粘贴:upload_router 与 batch_router 各自维护一份相同的分派代码,易漂移。
|
|
|
|
|
|
"""
|
|
|
|
|
|
import asyncio
|
|
|
|
|
|
|
|
|
|
|
|
from shared.utils.logger import get_logger
|
|
|
|
|
|
|
|
|
|
|
|
logger = get_logger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
from celery_tasks import process_stp_task
|
|
|
|
|
|
_use_celery = True
|
|
|
|
|
|
except ImportError:
|
|
|
|
|
|
process_stp_task = None
|
|
|
|
|
|
_use_celery = False
|
|
|
|
|
|
|
|
|
|
|
|
# 持有后台任务强引用,防止被 GC 回收;完成后自动移出
|
|
|
|
|
|
_background_tasks: set = set()
|
|
|
|
|
|
|
|
|
|
|
|
# API 进程内并发处理上限(celery 路径由 worker 并发数控制,不走这里)。
|
|
|
|
|
|
# asyncio.Semaphore 自 3.10 起惰性绑定事件循环,模块级创建安全;
|
|
|
|
|
|
# 本模块仅在 API 进程(单一事件循环)导入使用。
|
|
|
|
|
|
_dispatch_semaphore = asyncio.Semaphore(2)
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-09-16 17:55:04 +08:00
|
|
|
|
async def _run_with_limit(task_id: str, stp_file_id: int, process_params: dict):
|
2026-08-31 18:01:34 +08:00
|
|
|
|
async with _dispatch_semaphore:
|
|
|
|
|
|
from moldinsight.services.processing_service import processing_service
|
|
|
|
|
|
await processing_service.process_file_with_storage(
|
2026-09-16 17:55:04 +08:00
|
|
|
|
task_id, stp_file_id, process_params
|
2026-08-31 18:01:34 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-09-16 17:55:04 +08:00
|
|
|
|
def dispatch_processing(task_id: str, stp_file_id: int, process_params: dict):
|
|
|
|
|
|
"""调度 STP 处理任务:优先 Celery(进程隔离),否则 API 进程内 asyncio 后台执行。
|
|
|
|
|
|
|
|
|
|
|
|
入参只传 stp_file_id(D6):源文件由处理方按 PG 元数据从 RustFS 获取,
|
|
|
|
|
|
不再跨进程传节点本地路径——API 与 Celery worker 容器文件系统不互通,
|
|
|
|
|
|
传路径在容器化部署下必然失败。
|
|
|
|
|
|
"""
|
2026-08-31 18:01:34 +08:00
|
|
|
|
if _use_celery:
|
2026-09-16 17:55:04 +08:00
|
|
|
|
process_stp_task.delay(task_id, stp_file_id, process_params)
|
2026-08-31 18:01:34 +08:00
|
|
|
|
logger.info(f"[DISPATCH] Celery 任务已调度: task_id={task_id}")
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
task = asyncio.create_task(
|
2026-09-16 17:55:04 +08:00
|
|
|
|
_run_with_limit(task_id, stp_file_id, process_params)
|
2026-08-31 18:01:34 +08:00
|
|
|
|
)
|
|
|
|
|
|
_background_tasks.add(task)
|
|
|
|
|
|
task.add_done_callback(_background_tasks.discard)
|
|
|
|
|
|
logger.info(f"[DISPATCH] 进程内后台处理: task_id={task_id} (celery 未安装)")
|