Skip to content

Commit e2b1950

Browse files
committed
Fix #15: Long-running requests should time out
This change adds timeouts to methods in the LanguageService when a RunspaceHandle is requested but some other operation is taking too long. This allows the blocked request to cancel so that the editor client UI doesn't get blocked.
1 parent d935944 commit e2b1950

File tree

1 file changed

+32
-20
lines changed

1 file changed

+32
-20
lines changed

src/PowerShellEditorServices/Language/LanguageService.cs

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace Microsoft.PowerShell.EditorServices
1313
{
1414
using System.Management.Automation;
1515
using System.Management.Automation.Runspaces;
16-
16+
using System.Threading;
1717
/// <summary>
1818
/// Provides a high-level service for performing code completion and
1919
/// navigation operations on PowerShell scripts.
@@ -31,6 +31,8 @@ public class LanguageService
3131
private Dictionary<String, List<String>> CmdletToAliasDictionary;
3232
private Dictionary<String, String> AliasToCmdletDictionary;
3333

34+
const int DefaultWaitTimeoutMilliseconds = 5000;
35+
3436
#endregion
3537

3638
#region Constructors
@@ -87,7 +89,8 @@ public async Task<CompletionResults> GetCompletionsInFile(
8789
columnNumber);
8890

8991
RunspaceHandle runspaceHandle =
90-
await this.powerShellContext.GetRunspaceHandle();
92+
await this.powerShellContext.GetRunspaceHandle(
93+
new CancellationTokenSource(DefaultWaitTimeoutMilliseconds).Token);
9194

9295
CommandCompletion commandCompletion =
9396
AstOperations.GetCompletions(
@@ -193,8 +196,10 @@ public async Task<SymbolDetails> FindSymbolDetailsAtLocation(
193196

194197
if (symbolReference != null)
195198
{
199+
// Request a runspace handle with a short timeout
196200
RunspaceHandle runspaceHandle =
197-
await this.powerShellContext.GetRunspaceHandle();
201+
await this.powerShellContext.GetRunspaceHandle(
202+
new CancellationTokenSource(DefaultWaitTimeoutMilliseconds).Token);
198203

199204
symbolReference.FilePath = scriptFile.FilePath;
200205
symbolDetails = new SymbolDetails(symbolReference, runspaceHandle.Runspace);
@@ -431,8 +436,6 @@ public async Task<ParameterSetSignatures> FindParameterSetsInFile(
431436
}
432437
}
433438

434-
//public SymbolDetails GetSymbolDetails()
435-
436439
#endregion
437440

438441
#region Private Fields
@@ -444,28 +447,37 @@ private async Task GetAliases()
444447
{
445448
if (!this.areAliasesLoaded)
446449
{
447-
RunspaceHandle runspaceHandle = await this.powerShellContext.GetRunspaceHandle();
450+
try
451+
{
452+
RunspaceHandle runspaceHandle =
453+
await this.powerShellContext.GetRunspaceHandle(
454+
new CancellationTokenSource(DefaultWaitTimeoutMilliseconds).Token);
448455

449-
CommandInvocationIntrinsics invokeCommand = runspaceHandle.Runspace.SessionStateProxy.InvokeCommand;
450-
IEnumerable<CommandInfo> aliases = invokeCommand.GetCommands("*", CommandTypes.Alias, true);
456+
CommandInvocationIntrinsics invokeCommand = runspaceHandle.Runspace.SessionStateProxy.InvokeCommand;
457+
IEnumerable<CommandInfo> aliases = invokeCommand.GetCommands("*", CommandTypes.Alias, true);
451458

452-
runspaceHandle.Dispose();
459+
runspaceHandle.Dispose();
453460

454-
foreach (AliasInfo aliasInfo in aliases)
455-
{
456-
if (!CmdletToAliasDictionary.ContainsKey(aliasInfo.Definition))
457-
{
458-
CmdletToAliasDictionary.Add(aliasInfo.Definition, new List<String>() { aliasInfo.Name });
459-
}
460-
else
461+
foreach (AliasInfo aliasInfo in aliases)
461462
{
462-
CmdletToAliasDictionary[aliasInfo.Definition].Add(aliasInfo.Name);
463+
if (!CmdletToAliasDictionary.ContainsKey(aliasInfo.Definition))
464+
{
465+
CmdletToAliasDictionary.Add(aliasInfo.Definition, new List<String>() { aliasInfo.Name });
466+
}
467+
else
468+
{
469+
CmdletToAliasDictionary[aliasInfo.Definition].Add(aliasInfo.Name);
470+
}
471+
472+
AliasToCmdletDictionary.Add(aliasInfo.Name, aliasInfo.Definition);
463473
}
464474

465-
AliasToCmdletDictionary.Add(aliasInfo.Name, aliasInfo.Definition);
475+
this.areAliasesLoaded = true;
476+
}
477+
catch (TaskCanceledException)
478+
{
479+
// The wait for a RunspaceHandle has timed out, skip aliases for now
466480
}
467-
468-
this.areAliasesLoaded = true;
469481
}
470482
}
471483

0 commit comments

Comments
 (0)