Repository navigation
fix(runtime): read indexed servers before active ones in orphan cleanup - #1492
Conversation
Refs smart-mcp-proxy#1465 (item 2). cleanupOrphanedIndexEntries snapshotted the active server names before listing the indexed ones. When the startup pass ran late, a server registered and indexed between the two reads was deleted from the index as an orphan. That is what made TestRetrieveTools_ProfileWidenedByRawApplyIsSearchableImmediately return no hits on slow runners. Read the indexed names first: a server is registered before its tools are indexed, so one added mid-cleanup is either not indexed yet or already active. The comparison moves into findOrphanedIndexServers so the ordering is tested without relying on timing.
|
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
Thank you @Sriram-PR, this is a great fix and an unusually well-investigated one. What we liked:
We verified the change on top of current
It also got an independent cross-model review, which approved it. One small change we pushed to your branch. The reviewer pointed out that the new ordering comment slightly overstates the guarantee. It holds for servers newly added while cleanup runs. At startup, though, index entries persisted from a previous run can exist before the server's async re-registration finishes, so those can still be pruned and are then re-indexed by discovery (the same as before your change). We added a sentence to the comment to say exactly that. It's a comment-only edit, and your commits and authorship are untouched. The reviewer also noted a separate, older race: a server removed and re-added between the snapshot and Since this PR resolves only item 2, #1465 stays open for the remaining items. Thanks again for the careful work. Contributions like this are very welcome here, and we'd be glad to see more from you! |
Description
Fixes item 2 of #1465 (
TestRetrieveTools_ProfileWidenedByRawApplyIsSearchableImmediatelyreturning nil hits on slow runners).cleanupOrphanedIndexEntriesread the active server names first and the indexed names second. The startupbackgroundToolIndexinggoroutine runs it, so on a loaded runner it could take the active list before the test fixture'sLoadConfiguredServersregisteredaandb, then read the indexed list after the fixture seeded their tools, and delete them as orphans. The profile rebuild then found nothing forb. Caught with a stack trace on the delete:The same window exists outside tests: a server added while the startup cleanup runs could lose its freshly indexed tools until the next discovery pass.
Fix: read the indexed names first. A server is registered before its tools are indexed, so a server added mid-cleanup is either not in the indexed list yet or already in the active list read after it. A server that was really removed is still cleaned up. The two reads and the comparison moved into
findOrphanedIndexServersso the ordering can be tested without timing.Testing
I have tested these changes locally
I have added/updated tests that prove my fix is effective or my feature works
All existing tests pass
TestFindOrphanedIndexServers_ServerAddedDuringCleanupIsKeptadds a server right after the first read, whichever it is. It fails with the old order ([b]reported as orphan) and passes now.TestFindOrphanedIndexServers_RemovedServerIsOrphancovers the normal case.The original flake only shows up under load (the CI seed alone didn't reproduce it). With 16 parallel copies of the test and the CPU saturated it failed about 2% of runs before; with this branch 0 failures across 300 runs of the three
ProfileWidenedtests under the same load.go test -race ./internal/runtime/...passes, and golangci-lint with.github/.golangci.ymlreports nothing in the changed files.