SPB Git forge

spb/ai-atlas

Public
41commits 1branches 0releases
4.6 MBsize
maindefault branch
12 days agolast push
HTML 77.2% TypeScript 10.5% Python 9.6% JavaScript 2.5%

Worker: acquire the concurrency slot before claiming a job

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Simon-Pierre Boucher committed 13 days ago (Sep 11, 2026) parent 2ae7efc

1 changed file +8 −4

modified src/aiatlas/services/jobs.py +8 −4
@@ -80,7 +80,7 @@ async def run_worker(*, concurrency: int | None = None, kinds: list[str] | None
80 80 log.info("worker started", extra={"worker": worker, "kinds": kinds or "all"})
81 81
82 82 async def one(job: dict[str, Any]) -> None:
83 − async with sem:
83 + try:
84 84 fn = _HANDLERS.get(job["kind"])
85 85 if fn is None:
86 86 async with transaction() as conn:
@@ -94,15 +94,19 @@ async def run_worker(*, concurrency: int | None = None, kinds: list[str] | None
94 94 log.warning("job failed", extra={"job": job["id"], "kind": job["kind"], "error": str(exc)})
95 95 async with transaction() as conn:
96 96 await fail(conn, job, f"{exc.__class__.__name__}: {exc}\n{traceback.format_exc()[-1500:]}")
97 + finally:
98 + sem.release()
97 99
98 100 tasks: set[asyncio.Task[None]] = set()
99 101 while not stop.is_set():
100 − if sem.locked():
101 − await asyncio.sleep(0.5)
102 − continue
102 + await sem.acquire() # hold a slot BEFORE claiming, so concurrency bounds claims too
103 + if stop.is_set():
104 + sem.release()
105 + break
103 106 async with transaction() as conn:
104 107 job = await claim_next(conn, worker, kinds)
105 108 if job is None:
109 + sem.release()
106 110 try:
107 111 await asyncio.wait_for(stop.wait(), timeout=idle_sleep)
108 112 except TimeoutError:
109 113