| from __future__ import annotations |
| import asyncio, json, uuid, time |
| from sqlalchemy import select |
| from app.models.batch_job import BatchJob |
| from app.services.storage import async_session_maker |
| from app.services.connection_pool import get_client |
|
|
| MAX_BATCH_SIZE = 50 |
| MAX_CONCURRENT = 5 |
|
|
|
|
| async def create_batch(session, requests: list, model: str) -> dict: |
| if len(requests) > MAX_BATCH_SIZE: |
| requests = requests[:MAX_BATCH_SIZE] |
|
|
| batch_id = str(uuid.uuid4()) |
| total = len(requests) |
| results = [] |
| completed = 0 |
| failed = 0 |
|
|
| session.add(BatchJob( |
| id=batch_id, status="processing", total=total, |
| completed=0, failed=0, results="[]", |
| )) |
| await session.commit() |
|
|
| semaphore = asyncio.Semaphore(MAX_CONCURRENT) |
| client = get_client() |
|
|
| async def _process(req: dict, idx: int): |
| nonlocal completed, failed |
| async with semaphore: |
| try: |
| url = req.get("url", "") |
| method = req.get("method", "POST").upper() |
| headers = req.get("headers", {}) |
| body = req.get("body", {}) |
|
|
| if method == "GET": |
| resp = await client.get(url, headers=headers, timeout=120.0) |
| else: |
| resp = await client.post(url, headers=headers, json=body, timeout=120.0) |
|
|
| result = { |
| "index": idx, "status_code": resp.status_code, |
| "body": resp.text[:10000], |
| "error": "", |
| } |
| results.append(result) |
| if resp.is_success: |
| completed += 1 |
| else: |
| failed += 1 |
| except Exception as e: |
| results.append({"index": idx, "status_code": 0, "body": "", "error": str(e)}) |
| failed += 1 |
|
|
| tasks = [_process(req, i) for i, req in enumerate(requests)] |
| await asyncio.gather(*tasks) |
|
|
| status = "completed" if failed == 0 else ("partial" if completed > 0 else "failed") |
| await session.execute( |
| select(BatchJob).where(BatchJob.id == batch_id) |
| ) |
| row = (await session.execute(select(BatchJob).where(BatchJob.id == batch_id))).scalar_one() |
| row.status = status |
| row.completed = completed |
| row.failed = failed |
| row.results = json.dumps(results) |
| row.completed_at = time.time() |
| await session.commit() |
|
|
| return { |
| "batch_id": batch_id, |
| "status": status, |
| "total": total, |
| "completed": completed, |
| "failed": failed, |
| } |
|
|
|
|
| async def get_batch_history(session) -> list: |
| result = await session.execute( |
| select(BatchJob).order_by(BatchJob.created_at.desc()).limit(50) |
| ) |
| rows = result.scalars().all() |
| return [ |
| { |
| "batch_id": r.id, "status": r.status, |
| "total": r.total, "completed": r.completed, "failed": r.failed, |
| "created_at": r.created_at, "completed_at": r.completed_at, |
| } |
| for r in rows |
| ] |
|
|