Skip to content

Commit 171afa2

Browse files
committed
Fix #159: LanguageServer.Shutdown hangs on flush
The change fixes an issue in the LanguageServer's Shutdown method where buffered output in the OutputDebouncer gets flushed before shutting down. The problem here is the Wait call which blocks the message dispatcher thread from completing the OutputDebouncer.OnFlush method's SendEvent call. The fix is to change the Shutdown method to async so that the Flush call can be awaited, unblocking the message dispatcher thread's SynchronizationContext for the SendEvent call to complete.
1 parent a53e06b commit 171afa2

File tree

2 files changed

+13
-15
lines changed

2 files changed

+13
-15
lines changed

src/PowerShellEditorServices.Protocol/Server/LanguageServer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,10 @@ protected override void Initialize()
8080
this.SetRequestHandler(DebugAdapterMessages.EvaluateRequest.Type, this.HandleEvaluateRequest);
8181
}
8282

83-
protected override void Shutdown()
83+
protected override async Task Shutdown()
8484
{
8585
// Make sure remaining output is flushed before exiting
86-
this.outputDebouncer.Flush().Wait();
86+
await this.outputDebouncer.Flush();
8787

8888
Logger.Write(LogLevel.Normal, "Language service is shutting down...");
8989

src/PowerShellEditorServices.Protocol/Server/LanguageServerBase.cs

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,9 @@ protected override Task OnStart()
3434
return Task.FromResult(true);
3535
}
3636

37-
protected override Task OnStop()
37+
protected override async Task OnStop()
3838
{
39-
this.Shutdown();
40-
41-
return Task.FromResult(true);
39+
await this.Shutdown();
4240
}
4341

4442
/// <summary>
@@ -49,37 +47,37 @@ protected override Task OnStop()
4947

5048
/// <summary>
5149
/// Can be overridden by the subclass to provide shutdown
52-
/// logic before the server exits.
50+
/// logic before the server exits. Subclasses do not need
51+
/// to invoke or return the value of the base implementation.
5352
/// </summary>
54-
protected virtual void Shutdown()
53+
protected virtual Task Shutdown()
5554
{
5655
// No default implementation yet.
56+
return Task.FromResult(true);
5757
}
5858

59-
private Task HandleShutdownRequest(
59+
private async Task HandleShutdownRequest(
6060
object shutdownParams,
6161
RequestContext<object> requestContext)
6262
{
6363
// Allow the implementor to shut down gracefully
64-
this.Shutdown();
64+
await this.Shutdown();
6565

66-
return requestContext.SendResult(new object());
66+
await requestContext.SendResult(new object());
6767
}
6868

69-
private Task HandleExitNotification(
69+
private async Task HandleExitNotification(
7070
object exitParams,
7171
EventContext eventContext)
7272
{
7373
// Stop the server channel
74-
this.Stop();
74+
await this.Stop();
7575

7676
// Notify any waiter that the server has exited
7777
if (this.serverExitedTask != null)
7878
{
7979
this.serverExitedTask.SetResult(true);
8080
}
81-
82-
return Task.FromResult(true);
8381
}
8482
}
8583
}

0 commit comments

Comments
 (0)