Skip to content

Commit a9fe21f

Browse files
saschabuehrlerajbosCopilot
authored
fix: prevent loading stalls during session discovery (#545)
* fix: bound session discovery fs concurrency (fixes #542) * Update vscode-extension/src/sessionDiscovery.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix npm audit issues --------- Co-authored-by: Rob Bos <rajbos@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Rob Bos <raj.bos@gmail.com>
1 parent 025540c commit a9fe21f

File tree

2 files changed

+57
-33
lines changed

2 files changed

+57
-33
lines changed

vscode-extension/package-lock.json

Lines changed: 28 additions & 27 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vscode-extension/src/sessionDiscovery.ts

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,29 @@ export class SessionDiscovery {
4747
}
4848
}
4949

50+
/**
51+
* Run async tasks with bounded concurrency to avoid saturating the extension host.
52+
*/
53+
private async runWithConcurrency<T>(
54+
items: T[],
55+
fn: (item: T, index: number) => Promise<void>,
56+
limit = 8
57+
): Promise<void> {
58+
if (items.length === 0) { return; }
59+
let index = 0;
60+
const workers = Array.from({ length: Math.min(limit, items.length) }, async () => {
61+
while (index < items.length) {
62+
const i = index++;
63+
try {
64+
await fn(items[i], i);
65+
} catch (error) {
66+
this.deps.warn(`Failed to process session discovery item at index ${i}: ${error instanceof Error ? error.message : String(error)}`);
67+
}
68+
}
69+
});
70+
await Promise.all(workers);
71+
}
72+
5073
/**
5174
* Get all possible VS Code user data paths for all VS Code variants
5275
* Supports: Code (stable), Code - Insiders, VSCodium, remote servers, etc.
@@ -249,16 +272,16 @@ export class SessionDiscovery {
249272
}
250273

251274
try {
252-
// Scan all found VS Code paths for session files — process all variants in parallel
253-
await Promise.all(foundPaths.map(async (codeUserPath) => {
275+
// Scan all found VS Code paths for session files with bounded concurrency.
276+
await this.runWithConcurrency(foundPaths, async (codeUserPath) => {
254277
const pathName = path.basename(path.dirname(codeUserPath));
255278

256-
// Workspace storage sessions — scan all workspace dirs in parallel
279+
// Workspace storage sessions — also bounded to avoid spawning hundreds of FS ops at once.
257280
const workspaceStoragePath = path.join(codeUserPath, 'workspaceStorage');
258281
try {
259282
if (await this.pathExists(workspaceStoragePath)) {
260283
const workspaceDirs = await fs.promises.readdir(workspaceStoragePath);
261-
await Promise.all(workspaceDirs.map(async (workspaceDir) => {
284+
await this.runWithConcurrency(workspaceDirs, async (workspaceDir) => {
262285
const chatSessionsPath = path.join(workspaceStoragePath, workspaceDir, 'chatSessions');
263286
try {
264287
if (await this.pathExists(chatSessionsPath)) {
@@ -273,7 +296,7 @@ export class SessionDiscovery {
273296
} catch {
274297
// Ignore individual workspace dir errors
275298
}
276-
}));
299+
}, 6);
277300
}
278301
} catch (checkError) {
279302
this.deps.warn(`Could not check workspace storage path ${workspaceStoragePath}: ${checkError}`);
@@ -305,7 +328,7 @@ export class SessionDiscovery {
305328
} catch (checkError) {
306329
this.deps.warn(`Could not check Copilot Chat global storage path ${copilotChatGlobalPath}: ${checkError}`);
307330
}
308-
}));
331+
}, 4);
309332

310333
// Check for Copilot CLI session-state directory (new location for agent mode sessions)
311334
const copilotCliSessionPath = path.join(os.homedir(), '.copilot', 'session-state');

0 commit comments

Comments
 (0)