feat: replace asyncio.create_task with durable DB-backed job queue
Symbol indexing and GC now run in a separate worker process instead of fire-and-forget asyncio tasks inside uvicorn. This is the correct fix for the OOM crash that occurred when indexing 906 commits × 4000 files.
Architecture: - musehub_background_jobs table (migration 0032): pending/running/done/failed lifecycle with retry (up to 3 attempts), SKIP LOCKED for multi-worker safety - musehub/services/musehub_jobs.py: enqueue_job, claim_next_job, complete_job, fail_job — all thin DB operations, no business logic - musehub/worker.py: standalone Python process, polls every 1s, handles symbol_index and gc job types, crashes without affecting the web server - docker-compose.yml: new 'worker' service, 2 GiB memory limit (web server stays at 512 MiB), read_only filesystem, restarts on failure
Push handler change: Before: asyncio.create_task(_build_symbol_index_async(...)) After: await enqueue_job(session, repo_id, 'symbol_index', {'head': ...})
The push handler returns immediately — zero latency impact. The worker picks up and processes jobs asynchronously in its own memory space.
Tests: 7 new tests cover enqueue/claim/complete/fail/retry lifecycle and verify the push route calls enqueue_job (not asyncio.create_task) via spy.
0 comments
muse hub commit comment sha256:1b4d7cb810e752df1b1aec17e17dba03249d3499201f92ca284c0475d875bb05 --body "your comment"
No comments yet. Be the first to start the discussion.