Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 32 additions & 8 deletions src/managers/common/nativePythonFinder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,11 @@ class NativePythonFinderImpl implements NativePythonFinder {
private connection: rpc.MessageConnection;
private readonly pool: WorkerPool<NativePythonEnvironmentKind | Uri[] | undefined, NativeInfo[]>;
private cache: Map<string, NativeInfo[]> = new Map();
/**
* Tracks in-flight hard refreshes by cache key so concurrent callers share a
* single PET scan instead of queueing duplicate work.
*/
private inFlightRefreshes: Map<string, Promise<NativeInfo[]>> = new Map();
private startDisposables: Disposable[] = [];
private proc: ChildProcess | undefined;
private processExited: boolean = false;
Expand Down Expand Up @@ -555,20 +560,39 @@ class NativePythonFinderImpl implements NativePythonFinder {

private async handleHardRefresh(options?: NativePythonEnvironmentKind | Uri[]): Promise<NativeInfo[]> {
const key = this.getKey(options);

const inFlight = this.inFlightRefreshes.get(key);
if (inFlight) {
this.outputChannel.debug(`[Finder] Coalescing hard refresh with in-flight request for key: ${key}`);
return inFlight;
}

this.cache.delete(key);
if (!options) {
this.outputChannel.debug('[Finder] Refreshing all environments');
} else {
this.outputChannel.debug(`[Finder] Hard refresh for key: ${key}`);
}
const result = await this.pool.addToQueue(options);
// Validate result from worker pool
if (!result || !Array.isArray(result)) {
this.outputChannel.warn(`[pet] Worker pool returned invalid result type: ${typeof result}`);
return [];
}
this.cache.set(key, result);
return result;

// .finally clears the in-flight slot on both success AND failure paths so
// a rejected refresh does not poison the cache — the next call after a
// failure starts a fresh attempt, matching today's behavior.
const refreshPromise = this.pool
.addToQueue(options)
.then((result) => {
if (!result || !Array.isArray(result)) {
this.outputChannel.warn(`[pet] Worker pool returned invalid result type: ${typeof result}`);
return [] as NativeInfo[];
}
this.cache.set(key, result);
return result;
})
.finally(() => {
this.inFlightRefreshes.delete(key);
});

this.inFlightRefreshes.set(key, refreshPromise);
return refreshPromise;
}

private async handleSoftRefresh(options?: NativePythonEnvironmentKind | Uri[]): Promise<NativeInfo[]> {
Expand Down
Loading