diff --git a/package-lock.json b/package-lock.json index 0b2e4ac05b..4d50a31ae2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "powershell-preview", - "version": "2020.4.2", + "version": "2020.4.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f428a91059..7b707cde72 100644 --- a/package.json +++ b/package.json @@ -761,6 +761,11 @@ "default": null, "description": "An array of strings that enable experimental features in the PowerShell extension." }, + "powershell.developer.waitForSessionFileTimeoutSeconds": { + "type": "number", + "default": 240, + "description": "When the PowerShell extension is starting up, it checks for a session file in order to connect to the language server. This setting determines how long until checking for the session file times out. (default is 240 seconds or 4 minutes)" + }, "powershell.pester.useLegacyCodeLens": { "type": "boolean", "default": true, diff --git a/src/process.ts b/src/process.ts index d77fe8b8b8..80b849ef48 100644 --- a/src/process.ts +++ b/src/process.ts @@ -17,6 +17,10 @@ export class PowerShellProcess { return pspath.replace(new RegExp("'", "g"), "''"); } + // This is used to warn the user that the extension is taking longer than expected to startup. + // After the 15th try we've hit 30 seconds and should warn. + private static warnUserThreshold = 15; + public onExited: vscode.Event; private onExitedEmitter = new vscode.EventEmitter(); @@ -174,20 +178,36 @@ export class PowerShellProcess { return true; } - private waitForSessionFile(): Promise { - return new Promise((resolve, reject) => { - utils.waitForSessionFile(this.sessionFilePath, (sessionDetails, error) => { - utils.deleteSessionFile(this.sessionFilePath); + private sleep(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); + } - if (error) { - this.log.write(`Error occurred retrieving session file:\n${error}`); - return reject(error); - } + private async waitForSessionFile(): Promise { + // Determine how many tries by dividing by 2000 thus checking every 2 seconds. + const numOfTries = this.sessionSettings.developer.waitForSessionFileTimeoutSeconds / 2; + const warnAt = numOfTries - PowerShellProcess.warnUserThreshold; + // Check every 2 seconds + for (let i = numOfTries; i > 0; i--) { + if (utils.checkIfFileExists(this.sessionFilePath)) { this.log.write("Session file found"); - resolve(sessionDetails); - }); - }); + const sessionDetails = utils.readSessionFile(this.sessionFilePath); + utils.deleteSessionFile(this.sessionFilePath); + return sessionDetails; + } + + if (warnAt === i) { + vscode.window.showWarningMessage(`Loading the PowerShell extension is taking longer than expected. + If you're using privilege enforcement software, this can affect start up performance.`); + } + + // Wait a bit and try again + await this.sleep(2000); + } + + const err = "Timed out waiting for session file to appear."; + this.log.write(err); + throw new Error(err); } private onTerminalClose(terminal: vscode.Terminal) { diff --git a/src/settings.ts b/src/settings.ts index 9c81b2cc27..267134f84f 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -72,6 +72,7 @@ export interface IDeveloperSettings { bundledModulesPath?: string; editorServicesLogLevel?: string; editorServicesWaitForDebugger?: boolean; + waitForSessionFileTimeoutSeconds?: number; } export interface ISettings { @@ -142,6 +143,7 @@ export function load(): ISettings { bundledModulesPath: "../../../PowerShellEditorServices/module", editorServicesLogLevel: "Normal", editorServicesWaitForDebugger: false, + waitForSessionFileTimeoutSeconds: 240, }; const defaultCodeFoldingSettings: ICodeFoldingSettings = { diff --git a/src/utils.ts b/src/utils.ts index 57527cf529..bf3c107a66 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -45,7 +45,6 @@ export interface IEditorServicesSessionDetails { } export type IReadSessionFileCallback = (details: IEditorServicesSessionDetails) => void; -export type IWaitForSessionFileCallback = (details: IEditorServicesSessionDetails, error: string) => void; const sessionsFolder = path.resolve(__dirname, "..", "..", "sessions/"); const sessionFilePathPrefix = path.resolve(sessionsFolder, "PSES-VSCode-" + process.env.VSCODE_PID); @@ -69,25 +68,6 @@ export function writeSessionFile(sessionFilePath: string, sessionDetails: IEdito writeStream.close(); } -export function waitForSessionFile(sessionFilePath: string, callback: IWaitForSessionFileCallback) { - - function innerTryFunc(remainingTries: number, delayMilliseconds: number) { - if (remainingTries === 0) { - callback(undefined, "Timed out waiting for session file to appear."); - } else if (!checkIfFileExists(sessionFilePath)) { - // Wait a bit and try again - setTimeout( - () => { innerTryFunc(remainingTries - 1, delayMilliseconds); }, - delayMilliseconds); - } else { - // Session file was found, load and return it - callback(readSessionFile(sessionFilePath), undefined); - } - } - - // Try once every 2 seconds, 60 times - making two full minutes - innerTryFunc(60, 2000); -} export function readSessionFile(sessionFilePath: string): IEditorServicesSessionDetails { const fileContents = fs.readFileSync(sessionFilePath, "utf-8");