Skip to content

Commit d6212a3

Browse files
committed
Fix container timeout from firing unnecessarily (#11336)
* Fix container timeout from firing unnecessarily * Check for undefined for timer
1 parent 3106c54 commit d6212a3

File tree

2 files changed

+40
-19
lines changed

2 files changed

+40
-19
lines changed

news/2 Fixes/11334.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Error: Timeout is shown after running any widget more than once.

src/datascience-ui/ipywidgets/container.tsx

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ type Props = {
3434

3535
export class WidgetManagerComponent extends React.Component<Props> {
3636
private readonly widgetManager: WidgetManager;
37-
private readonly widgetSourceRequests = new Map<string, Deferred<void>>();
37+
private readonly widgetSourceRequests = new Map<
38+
string,
39+
{ deferred: Deferred<void>; timer: NodeJS.Timeout | number | undefined }
40+
>();
3841
private timedoutWaitingForWidgetsToGetLoaded?: boolean;
3942
private widgetsCanLoadFromCDN: boolean = false;
4043
private readonly loaderSettings = {
@@ -107,12 +110,19 @@ export class WidgetManagerComponent extends React.Component<Props> {
107110
sources.forEach((source) => {
108111
// We have fetched the script sources for all of these modules.
109112
// In some cases we might not have the source, meaning we don't have it or couldn't find it.
110-
let deferred = this.widgetSourceRequests.get(source.moduleName);
111-
if (!deferred) {
112-
deferred = createDeferred();
113-
this.widgetSourceRequests.set(source.moduleName, deferred);
113+
let request = this.widgetSourceRequests.get(source.moduleName);
114+
if (!request) {
115+
request = {
116+
deferred: createDeferred(),
117+
timer: undefined
118+
};
119+
this.widgetSourceRequests.set(source.moduleName, request);
120+
}
121+
request.deferred.resolve();
122+
if (request.timer !== undefined) {
123+
// tslint:disable-next-line: no-any
124+
clearTimeout(request.timer as any); // This is to make this work on Node and Browser
114125
}
115-
deferred.resolve();
116126
});
117127
}
118128
private registerScriptSourceInRequirejs(source?: WidgetScriptSource) {
@@ -180,10 +190,12 @@ export class WidgetManagerComponent extends React.Component<Props> {
180190
private loadWidgetScript(moduleName: string, moduleVersion: string): Promise<void> {
181191
// tslint:disable-next-line: no-console
182192
console.log(`Fetch IPyWidget source for ${moduleName}`);
183-
let deferred = this.widgetSourceRequests.get(moduleName);
184-
if (!deferred) {
185-
deferred = createDeferred<void>();
186-
this.widgetSourceRequests.set(moduleName, deferred);
193+
let request = this.widgetSourceRequests.get(moduleName);
194+
if (!request) {
195+
request = {
196+
deferred: createDeferred<void>(),
197+
timer: undefined
198+
};
187199

188200
// If we timeout, then resolve this promise.
189201
// We don't want the calling code to unnecessary wait for too long.
@@ -193,18 +205,26 @@ export class WidgetManagerComponent extends React.Component<Props> {
193205
// Possible user has ignored some UI prompt and things are now in a state of limbo.
194206
// This way thigns will fall over sooner due to missing widget sources.
195207
const timeoutTime = this.timedoutWaitingForWidgetsToGetLoaded
196-
? 10_000
208+
? 5_000
197209
: this.loaderSettings.timeoutWaitingForScriptToLoad;
198210

199-
setTimeout(() => {
200-
// tslint:disable-next-line: no-console
201-
console.error(`Timeout waiting to get widget source for ${moduleName}, ${moduleVersion}`);
202-
this.handleLoadError('<class>', moduleName, moduleVersion, new Error('Timeout'), true).ignoreErrors();
203-
if (deferred) {
204-
deferred.resolve();
211+
request.timer = setTimeout(() => {
212+
if (request && !request.deferred.resolved) {
213+
// tslint:disable-next-line: no-console
214+
console.error(`Timeout waiting to get widget source for ${moduleName}, ${moduleVersion}`);
215+
this.handleLoadError(
216+
'<class>',
217+
moduleName,
218+
moduleVersion,
219+
new Error(`Timeout getting source for ${moduleName}:${moduleVersion}`),
220+
true
221+
).ignoreErrors();
222+
request.deferred.resolve();
223+
this.timedoutWaitingForWidgetsToGetLoaded = true;
205224
}
206-
this.timedoutWaitingForWidgetsToGetLoaded = true;
207225
}, timeoutTime);
226+
227+
this.widgetSourceRequests.set(moduleName, request);
208228
}
209229
// Whether we have the scripts or not, send message to extension.
210230
// Useful telemetry and also we know it was explicity requestd by ipywidgest.
@@ -213,7 +233,7 @@ export class WidgetManagerComponent extends React.Component<Props> {
213233
{ moduleName, moduleVersion }
214234
);
215235

216-
return deferred.promise.catch((ex) =>
236+
return request.deferred.promise.catch((ex) =>
217237
// tslint:disable-next-line: no-console
218238
console.error(`Failed to load Widget Script from Extension for for ${moduleName}, ${moduleVersion}`, ex)
219239
);

0 commit comments

Comments
 (0)