Skip to content

Indexing pipeline is fully sequential — batch symbols and run embeds concurrently #67

Description

@GoodbyePlanet

Impact: High (performance)

The main indexing loop in `server/indexer/pipeline.py:192-248` processes one file at a time: blob fetch → await dense embed → await sparse embed → delete → upsert, then the next file. There is no `asyncio.gather`, no semaphore, and no accumulation of symbols across files into full embedding batches.

Providers support batches of 128 (`server/embeddings/voyage.py:15`, `openai.py:16`, `jina_api.py:16`), but a single file yields only a handful of symbols, so the pipeline sends dozens-to-hundreds of tiny requests instead of a few full ones. This is the largest performance problem in the codebase.

Recommended changes (in order of value)

  1. Fetch blobs concurrently with a bounded semaphore — the pattern already exists in `github_source.py` (`_walk_tree_recursive`).
  2. Accumulate `CodeSymbol`s across files and embed in batches of the provider batch size.
  3. At minimum, asyncio.gather the dense and sparse embed_batch calls (pipeline.py:221-224) — dense is network-bound and sparse runs in a thread executor (bm25.py:19-21), so they overlap for free.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions