-
Notifications
You must be signed in to change notification settings - Fork 294
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
Make a timeout for interrupt ask for a restart #4414
Conversation
Codecov Report
@@ Coverage Diff @@
## main #4414 +/- ##
=====================================
- Coverage 75% 75% -1%
=====================================
Files 392 392
Lines 25627 25704 +77
Branches 3661 3673 +12
=====================================
+ Hits 19371 19399 +28
- Misses 4753 4790 +37
- Partials 1503 1515 +12
|
@@ -118,6 +120,7 @@ export class CellExecution { | |||
private disposables: IDisposable[] = []; | |||
private cancelHandled = false; | |||
private requestHandlerChain = Promise.resolve(); | |||
private activeExecutions: { execution: Promise<void>; session: IJupyterSession }[] = []; |
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.
I've not played around with new native execution much, so this might just be a misunderstanding on my part (looking over it more now). But I thought that a new CellExecution was created each time we executed a notebook cell. So why would we be getting multiple active executions on one CellExecution?
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.
The way the code is structured it's possible? There's nothing that prevents (from the CellExecution class) there being multiple executions for the same cell. But the calling class does prevent that.
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.
I don't see how we can have more than one item in the array, if we do its incorrect or i'm mistaken.
Can we not have an array instead. As we create new instances of this class for each execution (even if we run the same cell multiple times).
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.
Will look into this, please note we have tests today to ensure users are presented with an option to restart the kernel when interrupt fails.
src/test/datascience/notebook/interrupRestart.vscode.test.ts
Don'nt understand the issue, will read that soon & review the code..
We have tests that do this today. So not sure what this is fixing. |
The test passes if the interrupt succeeds. The old code would ALWAYS think it succeeded while the cell UI would actually still be running. this line here: // Wait for interruption or message prompting to restart kernel to be displayed.
// Interrupt can fail sometimes and then we display message prompting user to restart kernel.
await waitForCondition(
async () => deferred.completed || showInformationMessage.called,
30_000, // Wait for completion or interrupt timeout.
'Execution not cancelled'
); If the interrupt succeeds, deferred.completed would be true. |
@@ -165,6 +168,23 @@ export class CellExecution { | |||
); | |||
} | |||
|
|||
public async interrupt(timeoutMs: number): Promise<InterruptResult> { | |||
// Go through our active executions and interrupt each one. | |||
const results = await Promise.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.
We might want to ensure this method cannot be called more than once & if already completed.
I.e. if this._interrupted || this._completed) { return false}
Where ``this._interruptedis a promise that contains the result for the previous
interrupt` call for this cell execution (i.e. all interrupts will be doing the same thing - pointing to the same promise)
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.
& once the promise resolves we might want to clear that propery.
This way if user clicks multiple times, they will get the samae interrupt promise.
After user gets the interrupt error message if they try again, it should start a new interrupt sequence (without using the same - previously resolved promise).
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.
Good idea.
@@ -394,7 +470,9 @@ export class CellExecution { | |||
private async execute(session: IJupyterSession, loggers: INotebookExecutionLogger[]) { | |||
const code = this.cell.document.getText(); | |||
traceCellMessage(this.cell, 'Send code for execution'); | |||
return this.executeCodeCell(code, session, loggers); | |||
const execution = this.executeCodeCell(code, session, loggers); | |||
this.activeExecutions.push({ execution, session }); |
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.
Might want to clear this property in the dispose method.
Not sure about this, as it works for me. |
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.
Minor issues,
- Single item in array
- Cache promise for interrupt (if user clicks interrupt multiple times)
@DonJayamanne can you have another look? |
For #4369
The jupyterNotebook class was being used for interrupting. The problem is the jupyterNotebook assumes it was the one that started an execution and waits for the last pending execution to finish before saying in interrupt succeeded. Since there wasn't any, interrupt returns super fast and doesn't wait for the keyboard exception.
Changed interrupt to happen in the cellExecution class instead.
Also added an interruptTimedOut event because interrupt doesn't actually go through the notebook editor (where the code lives to show a restart if a timeout occurs). This allows the UI for this to remain in the notebook editor.
Interrupt is working for me in native notebooks now but only if I make sure the jsonrpc stuff is setup.
package-lock.json
has been regenerated by runningnpm install
(if dependencies have changed).