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
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
"""并行打包队列管理"""
|
||||
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()
|
||||
Reference in New Issue
Block a user