Skip to content

fix(mcp): stop a replaced code engine's autosync loop - #25

Merged
wongk merged 2 commits into
mainfrom
fix/code-engine-autosync-leak
Sep 19, 2026
Merged

wongk merged 2 commits into
mainfrom
fix/code-engine-autosync-leak

Conversation

@wongk

@wongk wongk commented Sep 19, 2026

Copy link
Copy Markdown

Problem

code_search answered "code index … is being rebuilt (index-write lock is held)" for about two thirds of calls in symphony-alpha. Part of the cause is here.

Since 8ea1eb15, the MCP daemon rebuilds its cached CodeContextEngine whenever the index version moves. It never stopped the engine it replaced. Each engine runs an autosync thread, and that thread keeps the engine alive, so every index bump left one more loop behind. Each leaked loop polled the tree and spawned its own lc code index for every change, and those reindexes bumped the version again.

Measured on the live symphony-alpha daemon:

  • the index-write lock was held for 100% of a 150 s sample
  • the daemon started 36 extra reindex processes in that window
  • the daemon used about 22 CPU-hours in 26 hours

Reproduced in isolation: 5 version bumps left 6 live autosync loops, and one file edit started 6 reindex subprocesses.

Fix

  • VersionedEngineCache gains an on_evict hook. It is called for every value the cache lets go of (superseded, discarded or cleared), outside the cache lock.
  • The daemon's cache passes _retire_code_engine, which calls the new public CodeContextEngine.stop_autosync().

After the fix, the same reproduction leaves 1 loop and 1 reindex per change.

Tests

  • Unit tests cover the hook: called once on supersede, on discard and on clear, and a failing hook does not fail the lookup.
  • A gateway test drives _code_context_engine through a version bump and asserts the replaced engine was stopped.
  • A real-engine test counts live autosync threads after 4 index bumps: exactly 1. It lives in tests/infra/code_intel because tests/gateway/conftest.py forces autosync off.

All of them fail without the fix. They also catch two narrower breakages: the daemon not wiring the hook, and the cache not calling it.

The gateway and code-intel suites give the same 8 failures on this branch as on main (daemon socket races, installer, read budget, savings ledger), all present before this change.

Related

One of three independent fixes for code search failing on symphony-alpha: fix/code-engine-autosync-leak, fix/incremental-reindex-batched-deletes, fix/search-reads-during-reindex. Each is based on main, and all three merge cleanly in any order (checked with git merge-tree, and their new tests pass together on an octopus merge).

wongk and others added 2 commits September 18, 2026 15:03
Each index-version bump rebuilt the cached engine but never stopped the old
one; its autosync thread kept it alive, so every bump added a loop that polled
the tree and spawned its own reindex. On a large repo the index-write lock
stayed held and code_search answered 'index is being rebuilt'.
@wongk
wongk merged commit ee2c36d into main Sep 19, 2026
9 checks passed
@wongk
wongk deleted the fix/code-engine-autosync-leak branch September 19, 2026 13:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant