From b17da0a99586290be4dbdc710342fc989f712402 Mon Sep 17 00:00:00 2001 From: Daniel Falbel Date: Wed, 16 Oct 2024 14:19:29 -0300 Subject: [PATCH] Improve restarting behavior of the reticulate session. (#5019) Addresses https://github.com/posit-dev/positron/issues/4887 by making sure the correct order of action happens: 1. Shutdown the Reticulate Python kernel 2. Restart the R session 3. Start a new reticulate session --------- Signed-off-by: Daniel Falbel Co-authored-by: Jonathan --- .../positron-reticulate/src/extension.ts | 45 ++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/extensions/positron-reticulate/src/extension.ts b/extensions/positron-reticulate/src/extension.ts index 53fe330f2bf..12fc2ae5467 100644 --- a/extensions/positron-reticulate/src/extension.ts +++ b/extensions/positron-reticulate/src/extension.ts @@ -484,20 +484,45 @@ class ReticulateRuntimeSession implements positron.LanguageRuntimeSession { // tied to the R session. // We have to send a restart to the R session, and send a reticulate::repl_python() // command to it. - this.pythonSession.shutdown(positron.RuntimeExitReason.Restart); - await this.rSession.restart(); - const rSession = await getRSession(); - rSession.execute( - 'reticulate::repl_python()', - 'start-reticulate', - positron.RuntimeCodeExecutionMode.Interactive, - positron.RuntimeErrorBehavior.Continue + const restart = await positron.window.showSimpleModalDialogPrompt( + vscode.l10n.t('Restarting reticulate'), + vscode.l10n.t('This is will also restart the parent R session. Are you sure you want to continue?'), + vscode.l10n.t('Yes'), + vscode.l10n.t('No') ); + + if (!restart) { + throw new Error('Restart cancelled.'); + } + + // The events below will make sure that things occur in the right order: + // 1. shutdown the current reticulate session + // 2. restart the attached R session + // 3. start a new reticulate session. + this.pythonSession.onDidEndSession((sess) => { + this.rSession.restart(); + }); + + const disposeListener = this.rSession.onDidChangeRuntimeState(async (e) => { + if (e === positron.RuntimeState.Ready) { + this.rSession.execute( + 'reticulate::repl_python()', + 'start-reticulate', + positron.RuntimeCodeExecutionMode.Interactive, + positron.RuntimeErrorBehavior.Continue + ); + // This should only happen once, so we dispose of this event as soon + // as we have started reticulate. + disposeListener.dispose(); + } + }); + + await this.shutdown(positron.RuntimeExitReason.Shutdown); return; } - public async shutdown() { - await this.pythonSession.shutdown(positron.RuntimeExitReason.Shutdown); + public async shutdown(exitReason: positron.RuntimeExitReason) { + await this.pythonSession.shutdown(exitReason); // Tell Positron that the kernel has exit. When launching IPykernel from a standalone // process, when the kernel exits, then all of it's threads, specially the IOPub thread // holding the ZeroMQ sockets will cease to exist, and thus Positron identifies that the