gabriel / musehub public
feat BREAKING feat/background-job-queue #1 / 1
gabriel · 75 days ago · Apr 9, 2026 · Diff

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.

sha256:1b4d7cb810e752df1b1aec17e17dba03249d3499201f92ca284c0475d875bb05 sha
sha256:012389adc2e342fcb4affdba284ee90b09e7265d846a2584c4a120fde8e791e7 snapshot
← Older Oldest on feat/background-job-queue
All commits
Newer → Latest on feat/background-job-queue

0 comments

No comments yet. Be the first to start the discussion.

To add a comment, use the Muse CLI: muse hub commit comment sha256:1b4d7cb810e752df1b1aec17e17dba03249d3499201f92ca284c0475d875bb05 --body "your comment"