fix(core): dispose Scheduler to prevent McpProgress listener leak (#24870)

This commit is contained in:
Anjaligarhwal
2026-04-08 08:35:53 +05:30
committed by GitHub
parent 47c5d25d93
commit b9f1d832c8
6 changed files with 65 additions and 3 deletions
@@ -15,6 +15,7 @@ import type { MessageBus } from '../confirmation-bus/message-bus.js';
vi.mock('../scheduler/scheduler.js', () => ({
Scheduler: vi.fn().mockImplementation(() => ({
schedule: vi.fn().mockResolvedValue([{ status: 'success' }]),
dispose: vi.fn(),
})),
}));
@@ -125,6 +126,57 @@ describe('agent-scheduler', () => {
expect(schedulerConfig.toolRegistry).not.toBe(mainRegistry);
});
it('should dispose the scheduler after schedule completes', async () => {
const mockConfig = {
getPromptRegistry: vi.fn(),
getResourceRegistry: vi.fn(),
messageBus: mockMessageBus,
toolRegistry: mockToolRegistry,
} as unknown as Mocked<Config>;
const options = {
schedulerId: 'subagent-1',
toolRegistry: mockToolRegistry as unknown as ToolRegistry,
signal: new AbortController().signal,
};
await scheduleAgentTools(mockConfig as unknown as Config, [], options);
const schedulerInstance = vi.mocked(Scheduler).mock.results[0].value;
expect(schedulerInstance.dispose).toHaveBeenCalledOnce();
});
it('should dispose the scheduler even when schedule throws', async () => {
const scheduleError = new Error('schedule failed');
vi.mocked(Scheduler).mockImplementationOnce(
() =>
({
schedule: vi.fn().mockRejectedValue(scheduleError),
dispose: vi.fn(),
}) as unknown as Scheduler,
);
const mockConfig = {
getPromptRegistry: vi.fn(),
getResourceRegistry: vi.fn(),
messageBus: mockMessageBus,
toolRegistry: mockToolRegistry,
} as unknown as Mocked<Config>;
const options = {
schedulerId: 'subagent-1',
toolRegistry: mockToolRegistry as unknown as ToolRegistry,
signal: new AbortController().signal,
};
await expect(
scheduleAgentTools(mockConfig as unknown as Config, [], options),
).rejects.toThrow('schedule failed');
const schedulerInstance = vi.mocked(Scheduler).mock.results[0].value;
expect(schedulerInstance.dispose).toHaveBeenCalledOnce();
});
it('should create an AgentLoopContext that has a defined .config property', async () => {
const mockConfig = {
getPromptRegistry: vi.fn(),
+5 -1
View File
@@ -85,5 +85,9 @@ export async function scheduleAgentTools(
onWaitingForConfirmation,
});
return scheduler.schedule(requests, signal);
try {
return await scheduler.schedule(requests, signal);
} finally {
scheduler.dispose();
}
}