iOSBuildServer/backend/services/build_queue.py
shen 6f4f625c56 Initial commit: iOS Build Server
- FastAPI backend with build queue, WebSocket logs, task management
- Vue 3 frontend with build/config/history views
- Xcode project build automation with IPA export
- Fix: initialize build_dir before try block to ensure cleanup on early failure
2026-06-06 17:42:27 +08:00

81 lines
2.5 KiB
Python
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.

"""并行打包队列管理"""
import asyncio
from typing import Dict, Callable, Optional
from datetime import datetime
from .log_streamer import log_streamer
class BuildQueue:
"""打包任务队列"""
def __init__(self, max_concurrent: int = 2):
self._max_concurrent = max_concurrent
self._semaphore = asyncio.Semaphore(max_concurrent)
self._queue: asyncio.Queue = asyncio.Queue()
self._running_tasks: Dict[str, asyncio.Task] = {}
self._workers: list = []
self._started = False
async def start(self):
"""启动工作线程"""
if self._started:
return
self._started = True
for i in range(self._max_concurrent):
worker = asyncio.create_task(self._worker(f"worker-{i}"))
self._workers.append(worker)
async def _worker(self, name: str):
"""工作协程"""
while True:
task_id, build_func = await self._queue.get()
try:
await self._semaphore.acquire()
try:
self._running_tasks[task_id] = asyncio.current_task()
await build_func(task_id)
finally:
self._running_tasks.pop(task_id, None)
self._semaphore.release()
except Exception as e:
await log_streamer.emit_error(task_id, f"任务异常: {str(e)}")
finally:
self._queue.task_done()
async def submit(self, task_id: str, build_func: Optional[Callable] = None):
"""提交打包任务"""
if not self._started:
await self.start()
if build_func is None:
from .build_service import run_build_task
build_func = run_build_task
await self._queue.put((task_id, build_func))
await log_streamer.emit(task_id, "任务已加入队列,等待执行...")
def cancel(self, task_id: str):
"""取消任务"""
task = self._running_tasks.get(task_id)
if task and not task.done():
task.cancel()
def update_max_concurrent(self, new_max: int):
"""更新最大并发数"""
self._max_concurrent = new_max
# 注意:运行时修改需要重建 semaphore这里简化处理
# 实际使用时建议重启服务生效
@property
def queue_size(self) -> int:
return self._queue.qsize()
@property
def running_count(self) -> int:
return len(self._running_tasks)
# 全局单例
build_queue = BuildQueue()