Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix file browser model autostart, simplify poll start logic. #6401

Merged
merged 10 commits into from
May 24, 2019
6 changes: 6 additions & 0 deletions buildutils/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# @jupyterlab/buildutils

A JupyterLab package which provides utility functions that are used to compile
and build JupyterLab.

This package is only intended for use within a Node.js environments.
afshin marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 1 addition & 1 deletion docs/source/user/extensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ The following configurations may be present in this file:
2. ``disabledExtensions`` controls which extensions should not load at all.
3. ``deferredExtensions`` controls which extensions should not load until
they are required by something, irrespective of whether they set
``autostart`` to ``true``.
``autoStart`` to ``true``.

The value for the ``disabledExtensions`` and ``deferredExtensions`` fields
are an array of strings. The following sequence of checks are performed
Expand Down
7 changes: 5 additions & 2 deletions packages/coreutils/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# @jupyterlab/coreutils

A JupyterLab package which provides utility functions that are widely used across many
of the `@jupyterlab` packages. This includes (among other things) functions for manipulating paths, urls, and the notebook format.
A JupyterLab package which provides utility functions that are widely used
across many of the `@jupyterlab` packages. This includes (among other things)
functions for manipulating paths, urls, and the notebook format.

This package is intended for use within both Node.js and browser environments.
2 changes: 1 addition & 1 deletion packages/coreutils/src/activitymonitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export class ActivityMonitor<Sender, Args> implements IDisposable {
}, this._timeout);
}

private _timer = -1;
private _timer: any = -1;
private _timeout = -1;
private _sender: Sender;
private _args: Args;
Expand Down
70 changes: 32 additions & 38 deletions packages/coreutils/src/poll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,22 @@ import { IDisposable } from '@phosphor/disposable';

import { ISignal, Signal } from '@phosphor/signaling';

/**
* A function to defer an action immediately.
*/
const defer =
typeof requestAnimationFrame === 'function'
? requestAnimationFrame
: setImmediate;

/**
* A function to cancel a deferred action.
*/
const cancel =
typeof cancelAnimationFrame === 'function'
? cancelAnimationFrame
: clearImmediate;

Copy link
Member Author

@afshin afshin May 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is cribbed from PhosphorJS

It allows polling to work in the browser and in NodeJS.

/**
* A readonly poll that calls an asynchronous function with each tick.
*
Expand Down Expand Up @@ -112,9 +128,7 @@ export namespace IPoll {
| 'resolved'
| 'standby'
| 'started'
| 'stopped'
| 'when-rejected'
| 'when-resolved';
| 'stopped';

/**
* Definition of poll state at any given time.
Expand Down Expand Up @@ -183,23 +197,9 @@ export class Poll<T = any, U = any, V extends string = 'standby'>
};
this.name = options.name || Private.DEFAULT_NAME;

// Schedule poll ticks after `when` promise is settled.
(options.when || Promise.resolve())
.then(_ => {
if (this.isDisposed) {
return;
}

void this.schedule({ phase: 'when-resolved' });
})
.catch(reason => {
if (this.isDisposed) {
return;
}

console.warn(`Poll (${this.name}) started despite rejection.`, reason);
void this.schedule({ phase: 'when-rejected' });
});
if ('auto' in options ? options.auto : true) {
defer(() => void this.start());
}
}

/**
Expand Down Expand Up @@ -317,7 +317,7 @@ export class Poll<T = any, U = any, V extends string = 'standby'>
*/
refresh(): Promise<void> {
return this.schedule({
cancel: last => last.phase === 'refreshed',
cancel: ({ phase }) => phase === 'refreshed',
interval: Poll.IMMEDIATE,
phase: 'refreshed'
});
Expand Down Expand Up @@ -345,13 +345,6 @@ export class Poll<T = any, U = any, V extends string = 'standby'>
return;
}

// The `when` promise in the constructor options acts as a gate.
if (this.state.phase === 'constructed') {
if (next.phase !== 'when-rejected' && next.phase !== 'when-resolved') {
await this.tick;
}
}

// Check if the phase transition should be canceled.
if (next.cancel && next.cancel(this.state)) {
return;
Expand All @@ -373,7 +366,7 @@ export class Poll<T = any, U = any, V extends string = 'standby'>

// Clear the schedule if possible.
if (last.interval === Poll.IMMEDIATE) {
cancelAnimationFrame(this._timeout);
cancel(this._timeout);
} else {
clearTimeout(this._timeout);
}
Expand All @@ -393,7 +386,7 @@ export class Poll<T = any, U = any, V extends string = 'standby'>
};
this._timeout =
state.interval === Poll.IMMEDIATE
? requestAnimationFrame(execute)
? defer(execute)
: state.interval === Poll.NEVER
? -1
: setTimeout(execute, state.interval);
Expand All @@ -406,7 +399,8 @@ export class Poll<T = any, U = any, V extends string = 'standby'>
*/
start(): Promise<void> {
return this.schedule({
cancel: last => last.phase !== 'standby' && last.phase !== 'stopped',
cancel: ({ phase }) =>
phase !== 'constructed' && phase !== 'standby' && phase !== 'stopped',
interval: Poll.IMMEDIATE,
phase: 'started'
});
Expand All @@ -419,7 +413,7 @@ export class Poll<T = any, U = any, V extends string = 'standby'>
*/
stop(): Promise<void> {
return this.schedule({
cancel: last => last.phase === 'stopped',
cancel: ({ phase }) => phase === 'stopped',
interval: Poll.NEVER,
phase: 'stopped'
});
Expand Down Expand Up @@ -477,7 +471,7 @@ export class Poll<T = any, U = any, V extends string = 'standby'>
private _state: IPoll.State<T, U, V>;
private _tick = new PromiseDelegate<this>();
private _ticked = new Signal<this, IPoll.State<T, U, V>>(this);
private _timeout = -1;
private _timeout: any = -1;
}

/**
Expand Down Expand Up @@ -512,6 +506,11 @@ export namespace Poll {
* @typeparam V - The type to extend the phases supported by a poll.
*/
export interface IOptions<T, U, V extends string> {
/**
* Whether to begin polling automatically; defaults to `true`.
*/
auto?: boolean;

/**
* A factory function that is passed a poll tick and returns a poll promise.
*/
Expand Down Expand Up @@ -539,11 +538,6 @@ export namespace Poll {
* tick execution, but may be called by clients as well.
*/
standby?: Standby | (() => boolean | Standby);

/**
* If set, a promise which must resolve (or reject) before polling begins.
*/
when?: Promise<any>;
}
/**
* An interval value that indicates the poll should tick immediately.
Expand Down
1 change: 1 addition & 0 deletions packages/coreutils/src/ratelimiter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export abstract class RateLimiter<T, U> implements IRateLimiter<T, U> {
constructor(fn: () => T | Promise<T>, limit = 500) {
this.limit = limit;
this.poll = new Poll({
auto: false,
factory: async () => await fn(),
frequency: { backoff: false, interval: Poll.NEVER, max: Poll.NEVER },
standby: 'never'
Expand Down
3 changes: 2 additions & 1 deletion packages/coreutils/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"compilerOptions": {
"outDir": "lib",
"rootDir": "src",
"module": "commonjs"
"module": "commonjs",
"types": ["node"]
},
"files": ["src/plugin-schema.json"],
"include": ["src/*"]
Expand Down
12 changes: 8 additions & 4 deletions packages/services/src/kernel/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,26 +39,30 @@ export class KernelManager implements Kernel.IManager {

// Start model and specs polling with exponential backoff.
this._pollModels = new Poll({
auto: false,
factory: () => this.requestRunning(),
frequency: {
interval: 10 * 1000,
backoff: true,
max: 300 * 1000
},
name: `@jupyterlab/services:KernelManager#models`,
standby: options.standby || 'when-hidden',
when: this.ready
standby: options.standby || 'when-hidden'
});
this._pollSpecs = new Poll({
auto: false,
factory: () => this.requestSpecs(),
frequency: {
interval: 61 * 1000,
backoff: true,
max: 300 * 1000
},
name: `@jupyterlab/services:KernelManager#specs`,
standby: options.standby || 'when-hidden',
when: this.ready
standby: options.standby || 'when-hidden'
});
void this.ready.then(() => {
void this._pollModels.start();
void this._pollSpecs.start();
});
}

Expand Down
12 changes: 8 additions & 4 deletions packages/services/src/session/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,26 +41,30 @@ export class SessionManager implements Session.IManager {

// Start model and specs polling with exponential backoff.
this._pollModels = new Poll({
auto: false,
factory: () => this.requestRunning(),
frequency: {
interval: 10 * 1000,
backoff: true,
max: 300 * 1000
},
name: `@jupyterlab/services:SessionManager#models`,
standby: options.standby || 'when-hidden',
when: this.ready
standby: options.standby || 'when-hidden'
});
this._pollSpecs = new Poll({
auto: false,
factory: () => this.requestSpecs(),
frequency: {
interval: 61 * 1000,
backoff: true,
max: 300 * 1000
},
name: `@jupyterlab/services:SessionManager#specs`,
standby: options.standby || 'when-hidden',
when: this.ready
standby: options.standby || 'when-hidden'
});
void this.ready.then(() => {
void this._pollModels.start();
void this._pollSpecs.start();
});
}

Expand Down
7 changes: 5 additions & 2 deletions packages/services/src/terminal/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,18 @@ export class TerminalManager implements TerminalSession.IManager {

// Start polling with exponential backoff.
this._pollModels = new Poll({
auto: false,
factory: () => this.requestRunning(),
frequency: {
interval: 10 * 1000,
backoff: true,
max: 300 * 1000
},
name: `@jupyterlab/services:TerminalManager#models`,
standby: options.standby || 'when-hidden',
when: this.ready
standby: options.standby || 'when-hidden'
});
void this.ready.then(() => {
void this._pollModels.start();
});
}

Expand Down
Loading