Files
geMoldInsight/src/moldinsight/services/task_dispatcher.py
T

57 lines
2.2 KiB
Python
Raw Normal View History

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 未安装)")