Skip to content

fix(mcp): cancel the in-flight index before a force re-index instead of orphaning it - #429

Open
EricSeastrand wants to merge 1 commit into
zilliztech:masterfrom
EricSeastrand:upstream-pr/force-during-indexing
Open

fix(mcp): cancel the in-flight index before a force re-index instead of orphaning it#429
EricSeastrand wants to merge 1 commit into
zilliztech:masterfrom
EricSeastrand:upstream-pr/force-during-indexing

Conversation

@EricSeastrand

Copy link
Copy Markdown

Problem

handleIndexCodebase with force: true, on a codebase that is currently being indexed:

https://github.com/zilliztech/claude-context/blob/6fc318b/packages/mcp/src/handlers.ts#L377-L392

if (this.snapshotManager.getIndexingCodebases().includes(absolutePath)) {
    if (forceReindex) {
        console.log(`[FORCE-REINDEX] Clearing stale indexing state for '${absolutePath}'`);
        this.snapshotManager.removeCodebaseCompletely(absolutePath);
        this.snapshotManager.saveCodebaseSnapshot();
    } else {  }
}

Removing the snapshot entry does not stop the background task. The old run keeps embedding and writing chunks into the collection the new run is rebuilding, and its completion handler later writes stats for a run nobody is tracking. Two writers, one collection, no ordering.

This is exactly the orphaned-writer bug that #199 fixed for clear_index — and handleClearIndex already does it right:

const activeTask = this.indexingTasks.get(absolutePath);
if (activeTask) {
    activeTask.controller.abort();
    try { await activeTask.promise; } catch {  }
    this.indexingTasks.delete(absolutePath);
}

The indexingTasks map is already populated for every background index. The force path just never used it.

Change

The force branch now cancels and awaits wind-down before clearing the snapshot entry, mirroring handleClearIndex. No new machinery, no new state.

Unchanged: force still proceeds to re-index afterwards, and a non-force call on an in-flight index still returns "already being indexed in the background" without cancelling anything.

Test

packages/mcp/src/handlers.force-during-indexing.test.ts registers a fake in-flight task whose promise only settles after its abort signal fires, then calls the handler with force: true. Asserts:

  • the signal is aborted;
  • wind-down completes before the handler proceeds past the already-indexing branch;
  • the entry is removed from indexingTasks;
  • and a second case: a non-force call reports the in-flight index and leaves the controller untouched.

It fails on master (controller.signal.aborted === false) and passes with this change. pnpm --filter @zilliz/claude-context-mcp test → 8/8; tsc --noEmit clean.

…of orphaning it

`handleIndexCodebase` with `force: true` on a codebase that is currently being
indexed calls `removeCodebaseCompletely()` and carries on. That clears the
snapshot entry but does not stop the background task: it keeps embedding and
writing chunks into the collection the new run is rebuilding, and its
completion handler later writes stats for a run nobody is watching.

This is the orphaned-writer bug that zilliztech#199 fixed for `clear_index`, which does
it correctly — abort the `AbortController`, await the task's promise, then
touch the collection. The `indexingTasks` map added there already holds
everything needed; the force path just never learned to use it.

Force now cancels and awaits wind-down before clearing the snapshot entry and
starting the new index, mirroring `handleClearIndex`. Behaviour is otherwise
unchanged: force still proceeds, and a non-force call still returns
"already being indexed" without cancelling anything.

`handlers.force-during-indexing.test.ts` registers a fake in-flight task and
asserts the signal is aborted, wind-down completes before the handler moves
on, and the task is removed from `indexingTasks`. It fails on master (the
signal is never aborted).
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