فهرست منبع

Add Poll class to automatically poll and exponentially back off of failing poll requests.

Afshin Darian 6 سال پیش
والد
کامیت
b5919f6d42
3فایلهای تغییر یافته به همراه80 افزوده شده و 23 حذف شده
  1. 1 0
      packages/coreutils/src/index.ts
  2. 58 0
      packages/coreutils/src/poll.ts
  3. 21 23
      packages/services/src/session/manager.ts

+ 1 - 0
packages/coreutils/src/index.ts

@@ -8,6 +8,7 @@ export * from './markdowncodeblocks';
 export * from './nbformat';
 export * from './pageconfig';
 export * from './path';
+export * from './poll';
 export * from './settingregistry';
 export * from './statedb';
 export * from './text';

+ 58 - 0
packages/coreutils/src/poll.ts

@@ -0,0 +1,58 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import { IDisposable } from '@phosphor/disposable';
+
+export class Poll implements IDisposable {
+  constructor(options: Poll.IOptions) {
+    const { interval, max, poll } = options;
+
+    if (interval > max) {
+      throw new Error('Poll interval cannot exceed max interval length');
+    }
+
+    this._poll(poll, interval, max);
+  }
+
+  get isDisposed(): boolean {
+    return this._isDisposed;
+  }
+
+  dispose(): void {
+    if (this._isDisposed) {
+      return;
+    }
+    this._isDisposed = true;
+  }
+
+  private _poll(fn: () => Promise<any>, interval: number, max: number): void {
+    setTimeout(async () => {
+      if (this._isDisposed) {
+        return;
+      }
+
+      // Only execute promise if not in a hidden tab.
+      if (typeof document === 'undefined' || !document.hidden) {
+        try {
+          await fn();
+        } catch (error) {
+          const old = interval;
+          interval = Math.min(old * 2, max);
+          console.warn(`Poll error, raise interval from ${old} to ${interval}`);
+        }
+      }
+
+      this._poll(fn, interval, max);
+    }, interval);
+  }
+
+  private _isDisposed = false;
+}
+
+export namespace Poll {
+  export interface IOptions {
+    interval: number;
+    max: number;
+    poll: () => Promise<any>;
+  }
+}

+ 21 - 23
packages/services/src/session/manager.ts

@@ -1,6 +1,8 @@
 // Copyright (c) Jupyter Development Team.
 // Distributed under the terms of the Modified BSD License.
 
+import { Poll } from '@jupyterlab/coreutils';
+
 import { ArrayExt, IIterator, iter } from '@phosphor/algorithm';
 
 import { JSONExt } from '@phosphor/coreutils';
@@ -9,7 +11,7 @@ import { ISignal, Signal } from '@phosphor/signaling';
 
 import { Kernel } from '../kernel';
 
-import { ServerConnection } from '..';
+import { ServerConnection } from '../serverconnection';
 
 import { Session } from './session';
 
@@ -31,21 +33,17 @@ export class SessionManager implements Session.IManager {
       return this._refreshRunning();
     });
 
-    // Set up polling.
-    this._modelsTimer = (setInterval as any)(() => {
-      if (typeof document !== 'undefined' && document.hidden) {
-        // Don't poll when nobody's looking.
-        return;
-      }
-      return this._refreshRunning();
-    }, 10000);
-    this._specsTimer = (setInterval as any)(() => {
-      if (typeof document !== 'undefined' && document.hidden) {
-        // Don't poll when nobody's looking.
-        return;
-      }
-      return this._refreshSpecs();
-    }, 61000);
+    // Start model and specs polling with exponential backoff.
+    this._pollModels = new Poll({
+      interval: 10 * 1000,
+      max: 300 * 1000,
+      poll: () => this._refreshRunning()
+    });
+    this._pollSpecs = new Poll({
+      interval: 61 * 1000,
+      max: 305 * 1000,
+      poll: () => this._refreshSpecs()
+    });
   }
 
   /**
@@ -103,10 +101,10 @@ export class SessionManager implements Session.IManager {
       return;
     }
     this._isDisposed = true;
-    clearInterval(this._modelsTimer);
-    clearInterval(this._specsTimer);
-    Signal.clearData(this);
     this._models.length = 0;
+    this._pollModels.dispose();
+    this._pollSpecs.dispose();
+    Signal.clearData(this);
   }
 
   /**
@@ -337,13 +335,13 @@ export class SessionManager implements Session.IManager {
 
   private _isDisposed = false;
   private _models: Session.IModel[] = [];
+  private _pollModels: Poll;
+  private _pollSpecs: Poll;
+  private _readyPromise: Promise<void>;
+  private _runningChanged = new Signal<this, Session.IModel[]>(this);
   private _sessions = new Set<Session.ISession>();
   private _specs: Kernel.ISpecModels | null = null;
-  private _modelsTimer = -1;
-  private _specsTimer = -1;
-  private _readyPromise: Promise<void>;
   private _specsChanged = new Signal<this, Kernel.ISpecModels>(this);
-  private _runningChanged = new Signal<this, Session.IModel[]>(this);
 }
 
 /**