Skip to content

Commit 27cbd62

Browse files
committed
address comments
1 parent 23c4479 commit 27cbd62

1 file changed

Lines changed: 29 additions & 15 deletions

File tree

src/managers/common/nativePythonFinder.ts

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ const RESOLVE_TIMEOUT_MS = 30_000; // 30 seconds for single resolve
2626

2727
// CLI fallback timeout: generous budget since it's a full process spawn doing a full scan
2828
const CLI_FALLBACK_TIMEOUT_MS = 120_000; // 2 minutes
29+
// Limit concurrent resolve subprocesses to avoid CPU/memory pressure on machines with many envs
30+
const CLI_RESOLVE_CONCURRENCY = 4;
2931

3032
// Restart/recovery constants
3133
const MAX_RESTART_ATTEMPTS = 3;
@@ -885,13 +887,13 @@ class NativePythonFinderImpl implements NativePythonFinder {
885887
let parsed: { managers: NativeEnvManagerInfo[]; environments: NativeEnvInfo[] };
886888
try {
887889
parsed = parseRefreshCliOutput(stdout);
888-
} catch {
890+
} catch (ex) {
889891
sendTelemetryEvent(EventNames.PET_JSON_CLI_FALLBACK, stopWatch.elapsedTime, {
890892
operation: 'refresh',
891893
result: 'error',
892894
});
893-
this.outputChannel.error('[pet] JSON CLI fallback: Failed to parse find output:', stdout.slice(0, 500));
894-
throw new Error('Failed to parse PET find --json output');
895+
this.outputChannel.error('[pet] JSON CLI fallback: Failed to parse find output:', stdout.slice(0, 500), ex);
896+
throw new Error('Failed to parse PET find --json output', { cause: ex });
895897
}
896898

897899
const nativeInfo: NativeInfo[] = [];
@@ -901,13 +903,28 @@ class NativePythonFinderImpl implements NativePythonFinder {
901903
nativeInfo.push(manager);
902904
}
903905

904-
// Resolve incomplete environments in parallel, mirroring doRefreshAttempt's Promise.all pattern.
905-
const resolvePromises: Promise<void>[] = [];
906+
// Collect environments that need individual resolve calls.
907+
// Incomplete environments have an executable but are missing version or prefix.
908+
const toResolve: NativeEnvInfo[] = [];
906909
for (const env of parsed.environments ?? []) {
907910
if (env.executable && (!env.version || !env.prefix)) {
908-
// Environment has an executable but incomplete metadata — resolve individually
909-
resolvePromises.push(
910-
this.resolveViaJsonCli(env.executable)
911+
toResolve.push(env);
912+
} else {
913+
this.outputChannel.info(`[pet CLI] Discovered env: ${env.executable ?? env.prefix}`);
914+
nativeInfo.push(env);
915+
}
916+
}
917+
918+
// Resolve incomplete environments with bounded concurrency to avoid spawning too many
919+
// subprocesses at once on machines with many incomplete environments.
920+
// Each resolveViaJsonCli() spawns a new OS process, unlike server mode where all resolve
921+
// calls share a single long-lived process — so unbounded parallelism would cause CPU/memory
922+
// pressure. Process in batches of CLI_RESOLVE_CONCURRENCY.
923+
for (let i = 0; i < toResolve.length; i += CLI_RESOLVE_CONCURRENCY) {
924+
const batch = toResolve.slice(i, i + CLI_RESOLVE_CONCURRENCY);
925+
await Promise.all(
926+
batch.map((env) =>
927+
this.resolveViaJsonCli(env.executable!)
911928
.then((resolved) => {
912929
this.outputChannel.info(`[pet CLI] Resolved env: ${resolved.executable}`);
913930
nativeInfo.push(resolved);
@@ -919,13 +936,9 @@ class NativePythonFinderImpl implements NativePythonFinder {
919936
);
920937
nativeInfo.push(env);
921938
}),
922-
);
923-
} else {
924-
this.outputChannel.info(`[pet CLI] Discovered env: ${env.executable ?? env.prefix}`);
925-
nativeInfo.push(env);
926-
}
939+
),
940+
);
927941
}
928-
await Promise.all(resolvePromises);
929942

930943
sendTelemetryEvent(EventNames.PET_JSON_CLI_FALLBACK, stopWatch.elapsedTime, {
931944
operation: 'refresh',
@@ -1090,7 +1103,8 @@ export function parseResolveCliOutput(stdout: string, executable: string): Nativ
10901103
* @param options Optional refresh options: a kind filter string or an array of URIs to search.
10911104
* @param venvFolders Additional virtual environment folder paths to include when searching
10921105
* URI-based paths (needed because searchPaths may override environmentDirectories in PET).
1093-
* @returns The args array to pass to the PET binary (after 'find --json').
1106+
* @returns The args array to pass directly to the PET binary, starting with `['find', '--json']`
1107+
* followed by the positional search paths and configuration flags.
10941108
*/
10951109
export function buildFindCliArgs(
10961110
config: ConfigurationOptions,

0 commit comments

Comments
 (0)