Skip to content

Potential race condition with initialized handler #588

Closed
@andyleejordan

Description

@andyleejordan

So @rjmholt and I have been debugging an issue with the PowerShell extension after updating to v3.19, and we believe have tracked it down to a race condition. But we don't know if this is an issue with OmniSharp, or maybe even with the LSP spec itself.

We see that the Initialize request handler, for LSP2, sets Initialized:

// TODO:
if (_clientVersion == ClientVersion.Lsp2)
{
_serverReceiver.Initialized();
_initializeComplete.OnNext(result);
_initializeComplete.OnCompleted();
}

This made sense, because Initialize was a request and so the client can (and does) wait to hear from the server that Initialize was handled. When OmniSharp calls that initialized() method (for LSP2) then GetRequests() starts behaving "correctly" (handling all notifications and requests):

public override (IEnumerable<Renor> results, bool hasResponse) GetRequests(JToken container)
{
if (_initialized) return base.GetRequests(container);
var newResults = new List<Renor>();
// Based on https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md#initialize-request
var (results, hasResponse) = base.GetRequests(container);
foreach (var item in results)
{
switch (item)
{
case { IsResponse: true }:
case { IsRequest: true, Request: { Method: GeneralNames.Initialize } }:
case { IsNotification: true, Notification: { Method: GeneralNames.Initialized } }:
newResults.Add(item);
break;
case { IsRequest: true, Request: { } }:
newResults.Add(new ServerNotInitialized(item.Request!.Method));
_logger.LogWarning("Unexpected request {Method} {@Request}", item.Request.Method, item.Request);
break;
case { IsNotification: true, Notification: { } }:
_logger.LogWarning("Unexpected notification {Method} {@Request}", item.Notification.Method, item.Notification);
break;
case { IsError: true, Error: { } }:
_logger.LogWarning("Unexpected error {Method} {@Request}", item.Error.Method, item.Error);
break;
default:
_logger.LogError("Unexpected Renor {@Renor}", item);
break;
}
}
return ( newResults, hasResponse );
}

But then this was changed for LSP3, we have an Initialized (note the D) handler for the Initialized notification (which the client cannot wait on). This is problematic because the client then sends more notifications which race the server's handler for the Initialized notification, and this race ends up in the requests not being handled, as evidenced by the responses "Unexpected request" and "Unexpected notification" in GetRequests.

public Task<Unit> Handle(InitializedParams @params, CancellationToken token)
{
if (_clientVersion == ClientVersion.Lsp3)
{
_serverReceiver.Initialized();
_initializeComplete.OnNext(ServerSettings);
_initializeComplete.OnCompleted();
}
return Unit.Task;
}

This correlates with the logs we have when we see a bug in the PowerShell extension:

2021-05-06 11:41:07.210 -07:00 [DBG] Finding descriptors for initialize
2021-05-06 11:41:07.382 -07:00 [DBG] Queueing "Serial":initialize:0 request for processing
2021-05-06 11:41:07.428 -07:00 [DBG] Starting: Processing request initialize 0
2021-05-06 11:41:07.444 -07:00 [DBG] Starting: Routing Request (0) initialize
2021-05-06 11:41:08.131 -07:00 [DBG] Finished: Routing Request (0) initialize in 687ms
2021-05-06 11:41:08.131 -07:00 [DBG] Finished: Processing request initialize 0 in 702ms
2021-05-06 11:41:08.211 -07:00 [DBG] Finding descriptors for initialized
2021-05-06 11:41:08.211 -07:00 [DBG] Queueing "Serial":initialized request for processing
2021-05-06 11:41:08.232 -07:00 [WRN] Unexpected notification workspace/didChangeConfiguration {"Method":"workspace/didChangeConfiguration","Params":[[[[[[[[[]],[[]]]],[[]],[[]],[[]],[[]],[[]],[[[[]],[[]]]],[[]],[[]],[[]],[[[[]]]],[[]],[[]],[[[[]],[[]]]],[[[[]],[[]]]],[[[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]]]],[[[[]],[[]],[[]],[[]],[[]]]],[[[[]]]],[[[[]],[[]],[[]],[[]],[[]]]],[[[[]],[[]],[[]]]],[[[[]],[[]]]]]],[[[[[[]]]],[[[[]],[[]],[[]],[[]],[[]]]],[[[[]],[[]]]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[[[]],[[]],[[]],[[]]]],[[]],[[]],[[]],[[]],[[]],[[[[]]]]]],[[[[[[]],[[]],[[]]]],[[]],[[]],[[]],[[]],[[]],[[[[]],[[]],[[null]]]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[[[]],[[]],[[]]]],[[]]]]]]],"TraceParent":null,"TraceState":null,"$type":"Notification"}
2021-05-06 11:41:08.233 -07:00 [WRN] Unexpected request powerShell/getVersion {"Id":1,"Method":"powerShell/getVersion","Params":null,"TraceParent":null,"TraceState":null,"$type":"Request"}
2021-05-06 11:41:08.234 -07:00 [WRN] Tried to send request or notification before initialization was completed and will be sent later {"Id":null,"Error":{"Code":-32002,"Data":null,"Message":"Server Not Initialized","$type":"ErrorMessage"},"Method":"powerShell/getVersion","$type":"ServerNotInitialized"}
2021-05-06 11:41:08.234 -07:00 [DBG] Starting: Processing notification initialized
2021-05-06 11:41:08.243 -07:00 [DBG] Starting: Routing Notification initialized
2021-05-06 11:41:08.366 -07:00 [DBG] Finished: Routing Notification initialized in 132ms
2021-05-06 11:41:08.366 -07:00 [DBG] Finished: Processing notification initialized in 141ms

We think this may be related to #556, @david-driscoll was there any update on your investigation into that issue? @majastrz does any of this make sense to you and sound related to your issue?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions