Skip to content

Commit 6be28bc

Browse files
Make the different refresh scenarios a bit easier to follow.
1 parent a70819b commit 6be28bc

File tree

1 file changed

+47
-36
lines changed

1 file changed

+47
-36
lines changed

src/client/pythonEnvironments/base/locators/composite/cachingLocator.ts

Lines changed: 47 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export class CachingLocator implements ILocator {
7171
this.opts = normalizeCachingLocatorOptions(opts);
7272
// eslint-disable-next-line @typescript-eslint/no-use-before-define
7373
this.looper = new BackgroundLooper({
74-
runDefault: () => this.doRefresh(),
74+
runDefault: () => this.refresh(),
7575
retry: {
7676
intervalms: this.opts.refreshRetryMinutes * 60 * 1000,
7777
},
@@ -96,8 +96,20 @@ export class CachingLocator implements ILocator {
9696

9797
await this.cache.initialize();
9898
this.looper.start();
99-
await this.initialRefresh();
100-
this.locator.onChanged((event) => this.handleChange(event));
99+
100+
this.locator.onChanged((event) => this.ensureCurrentRefresh(event));
101+
102+
// Do the initial refresh.
103+
const envs = this.cache.getAllEnvs();
104+
if (envs !== undefined) {
105+
this.initializing.resolve();
106+
await this.ensureRecentRefresh();
107+
} else {
108+
// There is nothing in the cache, so we must wait for the
109+
// initial refresh to finish before allowing iteration.
110+
await this.ensureRecentRefresh();
111+
this.initializing.resolve();
112+
}
101113
}
102114

103115
public dispose(): void {
@@ -134,7 +146,7 @@ export class CachingLocator implements ILocator {
134146
const envs = this.cache.getAllEnvs();
135147
if (envs !== undefined) {
136148
envs.push(resolved);
137-
await this.update(envs);
149+
await this.updateCache(envs);
138150
}
139151
}
140152
return resolved;
@@ -183,40 +195,62 @@ export class CachingLocator implements ILocator {
183195
}
184196

185197
/**
186-
* Trigger a refresh of the cache from the downstream locator.
198+
* Maybe trigger a refresh of the cache from the downstream locator.
187199
*
188-
* Note that if a refresh has already been requested or is currently
189-
* running, this is a noop.
200+
* If a refresh isn't already running then we request a refresh and
201+
* wait for it to finish. Otherwise we do not make a new request,
202+
* but instead only wait for the last requested refresh to complete.
190203
*/
191-
private refresh(): Promise<void> {
204+
private ensureRecentRefresh(): Promise<void> {
192205
// Re-use the last req in the queue if possible.
193206
const last = this.looper.getLastRequest();
194207
if (last !== undefined) {
195208
const [, promise] = last;
196209
return promise;
197210
}
198211
// The queue is empty so add a new request.
199-
const [, waitUntilDone] = this.looper.addRequest();
212+
const [, waitUntilDone] = this.looper.addRequest(() => this.refresh());
200213
return waitUntilDone;
201214
}
202215

216+
/**
217+
* Maybe trigger a refresh of the cache from the downstream locator.
218+
*
219+
* Make sure that a completely new refresh will be started soon and
220+
* wait for it to finish. If a refresh isn't already running then
221+
* we start one and wait for it to finish. If one is already
222+
* running then we make sure a new one is requested to start after
223+
* that and wait for it to finish. That means if one is already
224+
* waiting in the queue then we wait for that one instead of making
225+
* a new request.
226+
*/
227+
private ensureCurrentRefresh(event?: PythonEnvsChangedEvent): void {
228+
const req = this.looper.getNextRequest();
229+
if (req === undefined) {
230+
// There isn't already a pending request (due to an
231+
// onChanged event), so we add one.
232+
this.looper.addRequest(() => this.refresh(event));
233+
}
234+
// Otherwise let the pending request take care of it.
235+
}
236+
203237
/**
204238
* Immediately perform a refresh of the cache from the downstream locator.
205239
*
206-
* It does not matter if another refresh is already
240+
* It does not matter if another refresh is already running.
207241
*/
208-
private async doRefresh(
242+
private async refresh(
209243
event?: PythonEnvsChangedEvent,
210244
): Promise<void> {
211245
const iterator = this.locator.iterEnvs();
212246
const envs = await getEnvs(iterator);
213-
await this.update(envs, event);
247+
await this.updateCache(envs, event);
214248
}
215249

216250
/**
217251
* Set the cache to the given envs, flush, and emit an onChanged event.
218252
*/
219-
private async update(
253+
private async updateCache(
220254
envs: PythonEnvInfo[],
221255
event?: PythonEnvsChangedEvent,
222256
): Promise<void> {
@@ -225,29 +259,6 @@ export class CachingLocator implements ILocator {
225259
await this.cache.flush();
226260
this.watcher.fire(event || {}); // Emit an "onCHanged" event.
227261
}
228-
229-
private handleChange(event: PythonEnvsChangedEvent): void {
230-
const req = this.looper.getNextRequest();
231-
if (req === undefined) {
232-
// There isn't already a pending request (due to an
233-
// onChanged event), so we add one.
234-
this.looper.addRequest(() => this.doRefresh(event));
235-
}
236-
// Otherwise let the pending request take care of it.
237-
}
238-
239-
private async initialRefresh(): Promise<void> {
240-
const envs = this.cache.getAllEnvs();
241-
if (envs !== undefined) {
242-
this.initializing.resolve();
243-
await this.refresh();
244-
} else {
245-
// There is nothing in the cache, so we must wait for the
246-
// initial refresh to finish before allowing iteration.
247-
await this.refresh();
248-
this.initializing.resolve();
249-
}
250-
}
251262
}
252263

253264
type RequestID = number;

0 commit comments

Comments
 (0)