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
Use new Poll class for filebrowser contents polling. #6305
Changes from 2 commits
8a93826
07d7b4d
e3ee844
627b1db
99faafa
be4cc1a
6746f7d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,8 @@ import { | |
IChangedArgs, | ||
IStateDB, | ||
PathExt, | ||
PageConfig | ||
PageConfig, | ||
Poll | ||
} from '@jupyterlab/coreutils'; | ||
|
||
import { IDocumentManager, shouldOverwrite } from '@jupyterlab/docmanager'; | ||
|
@@ -87,8 +88,7 @@ export class FileBrowserModel implements IDisposable { | |
format: 'text' | ||
}; | ||
this._state = options.state || null; | ||
this._baseRefreshDuration = | ||
options.refreshInterval || DEFAULT_REFRESH_INTERVAL; | ||
const refreshInterval = options.refreshInterval || DEFAULT_REFRESH_INTERVAL; | ||
|
||
const { services } = options.manager; | ||
services.contents.fileChanged.connect(this._onFileChanged, this); | ||
|
@@ -103,8 +103,21 @@ export class FileBrowserModel implements IDisposable { | |
} | ||
}; | ||
window.addEventListener('beforeunload', this._unloadEventListener); | ||
this._scheduleUpdate(); | ||
this._startTimer(); | ||
this._poll = new Poll({ | ||
factory: async () => { | ||
const date = new Date().getTime(); | ||
if (date - this._lastRefresh < MIN_REFRESH) { | ||
return; | ||
} | ||
return this.refresh(); | ||
}, | ||
frequency: { | ||
interval: refreshInterval, | ||
backoff: true, | ||
max: 300 * 1000 | ||
}, | ||
standby: 'when-hidden' | ||
}); | ||
} | ||
|
||
/** | ||
|
@@ -198,7 +211,7 @@ export class FileBrowserModel implements IDisposable { | |
} | ||
window.removeEventListener('beforeunload', this._unloadEventListener); | ||
this._isDisposed = true; | ||
clearTimeout(this._timeoutId); | ||
this._poll.dispose(); | ||
this._sessions.length = 0; | ||
this._items.length = 0; | ||
Signal.clearData(this); | ||
|
@@ -227,7 +240,6 @@ export class FileBrowserModel implements IDisposable { | |
*/ | ||
refresh(): Promise<void> { | ||
this._lastRefresh = new Date().getTime(); | ||
this._requested = false; | ||
return this.cd('.'); | ||
} | ||
|
||
|
@@ -269,7 +281,6 @@ export class FileBrowserModel implements IDisposable { | |
if (this.isDisposed) { | ||
return; | ||
} | ||
this._refreshDuration = this._baseRefreshDuration; | ||
this._handleContents(contents); | ||
this._pendingPath = null; | ||
if (oldValue !== newValue) { | ||
|
@@ -296,7 +307,6 @@ export class FileBrowserModel implements IDisposable { | |
this._connectionFailure.emit(error); | ||
return this.cd('/'); | ||
} else { | ||
this._refreshDuration = this._baseRefreshDuration * 10; | ||
this._connectionFailure.emit(error); | ||
} | ||
}); | ||
|
@@ -586,7 +596,7 @@ export class FileBrowserModel implements IDisposable { | |
|
||
// If either the old value or the new value is in the current path, update. | ||
if (value) { | ||
this._scheduleUpdate(); | ||
this._poll.refresh(); | ||
ian-r-rose marked this conversation as resolved.
Show resolved
Hide resolved
|
||
this._populateSessions(sessions.running()); | ||
this._fileChanged.emit(change); | ||
return; | ||
|
@@ -605,38 +615,6 @@ export class FileBrowserModel implements IDisposable { | |
}); | ||
} | ||
|
||
/** | ||
* Start the internal refresh timer. | ||
*/ | ||
private _startTimer(): void { | ||
this._timeoutId = window.setInterval(() => { | ||
if (this._requested) { | ||
void this.refresh(); | ||
return; | ||
} | ||
if (document.hidden) { | ||
// Don't poll when nobody's looking. | ||
return; | ||
} | ||
let date = new Date().getTime(); | ||
if (date - this._lastRefresh > this._refreshDuration) { | ||
void this.refresh(); | ||
} | ||
}, MIN_REFRESH); | ||
} | ||
|
||
/** | ||
* Handle internal model refresh logic. | ||
*/ | ||
private _scheduleUpdate(): void { | ||
let date = new Date().getTime(); | ||
if (date - this._lastRefresh > MIN_REFRESH) { | ||
void this.refresh(); | ||
} else { | ||
this._requested = true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah, so it actually was doing a debounce, in that if we tried to schedule an update too soon, it would note it and follow up with an update at some point in the future. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it was doing that. Note, however, that the user clicking There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, the original intent was for the auto-poll to not happen too soon after a user or programmatically triggered poll. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then we should be okay with deleting the logic entirely, then. If a user clicking on the refresh button calls the poll refresh, the poll knows about the refresh and its interval starts over again. |
||
} | ||
} | ||
|
||
private _connectionFailure = new Signal<this, Error>(this); | ||
private _fileChanged = new Signal<this, Contents.IChangedArgs>(this); | ||
private _items: Contents.IModel[] = []; | ||
|
@@ -648,18 +626,15 @@ export class FileBrowserModel implements IDisposable { | |
private _pendingPath: string | null = null; | ||
private _refreshed = new Signal<this, void>(this); | ||
private _lastRefresh = -1; | ||
private _requested = false; | ||
private _sessions: Session.IModel[] = []; | ||
private _state: IStateDB | null = null; | ||
private _timeoutId = -1; | ||
private _refreshDuration: number; | ||
private _baseRefreshDuration: number; | ||
private _driveName: string; | ||
private _isDisposed = false; | ||
private _restored = new PromiseDelegate<void>(); | ||
private _uploads: IUploadModel[] = []; | ||
private _uploadChanged = new Signal<this, IChangedArgs<IUploadModel>>(this); | ||
private _unloadEventListener: (e: Event) => string; | ||
private _poll: Poll; | ||
} | ||
|
||
/** | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of this logic can go away with the new Poll class, I think. It's sufficient to just call the update method. When we want to have the poll immediately refresh, we call the poll's refresh method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, good point. It also does some logic around a minimum refresh interval, which I tried to keep intact.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We used to have a minimum interval option in Poll, but it didn't handle manual refreshes (it assumed a manual refresh was always immediate). Perhaps we add a minimum refresh interval to Poll for this debouncing. I think it would be pretty straightforward - the poll refresh() method would just schedule using logic like here.
So this logic isn't really a true debounce, in that it doesn't schedule a refresh according to MIN_REFRESH, it simply ignores requests if they are too soon after the last tick. That's perhaps a little frustrating - you click and click and click, and if you stop clicking before MIN_REFRESH, it's like you never clicked at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually, it's a bit more complicated for Poll, since we really want to debounce the callback (and every time we are about to call the callback, we check to see if we should go into standby, etc.). So that means the Poll should really be storing the last time it called the callback and make sure it's not calling the callback more often than it should.