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%

admin requeue-dead: honour the dedupe partial unique index

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Simon-Pierre Boucher committed 12 days ago (Sep 12, 2026) parent 8a8af96

1 changed file +11 −3

modified src/aiatlas/api/routers/admin.py +11 −3
@@ -262,10 +262,18 @@ async def retry_job(job_id: str) -> dict[str, Any]:
262 262
263 263 @router.post("/jobs/requeue-dead")
264 264 async def requeue_dead(kind: str | None = None) -> dict[str, Any]:
265 − where = "status = 'dead'" + (" and kind = :k" if kind else "")
265 + where = "j.status = 'dead'" + (" and j.kind = :k" if kind else "")
266 266 async with transaction() as conn:
267 − n = await fetch_val(conn, f"with u as (update jobs set status = 'queued', attempts = 0, error = null, locked_by = null, locked_at = null, finished_at = null, run_after = now() "
268 − f"where {where} returning 1) select count(*) from u", k=kind)
267 + # respect the partial unique index on dedupe_key (queued|running): skip dead jobs already superseded by a live one,
268 + # and requeue only one dead job per dedupe_key (the most recent); the other duplicates are closed as superseded.
269 + n = await fetch_val(conn, f"""with pick as (
270 + select distinct on (coalesce(j.dedupe_key, j.id)) j.id from jobs j
271 + where {where} and (j.dedupe_key is null or not exists (select 1 from jobs q where q.dedupe_key = j.dedupe_key and q.status in ('queued','running')))
272 + order by coalesce(j.dedupe_key, j.id), j.created_at desc),
273 + u as (update jobs set status = 'queued', attempts = 0, error = null, locked_by = null, locked_at = null, finished_at = null, run_after = now()
274 + where id in (select id from pick) returning 1)
275 + select count(*) from u""", k=kind)
276 + await execute(conn, f"update jobs j set status = 'done', error = coalesce(error, '') || ' [superseded]' where {where}", k=kind)
269 277 return {"requeued": int(n or 0)}
270 278
271 279
272 280