Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client: duplicate messages sent after server restart #342

Closed
nrc opened this issue Apr 23, 2018 · 13 comments
Closed

Client: duplicate messages sent after server restart #342

nrc opened this issue Apr 23, 2018 · 13 comments
Labels
bug Issue identified by VS Code Team member as probable bug
Milestone

Comments

@nrc
Copy link

nrc commented Apr 23, 2018

STR: start an extension with a language server (I use the Rust Language Server but I believe any extension/language server would do). Kill the language server process. The client restarts the server (as it should), but now every message (notification or request) is duplicated. If you kill the server again, you get three of each message, and so forth.

From looking at the source code for the client, it looks to me that when the client restarts the server it should properly cleanup the connection, but does not (so handlers are not removed). The connection is re-initialized, but by calling onRequest, onNotification, etc. the client is installing extra copies of the handlers into the connection, not replacing the previous handlers. So, when a message is sent to the connection it is dispatched multiple times to the server.

cc microsoft/vscode#48309

@dbaeumer
Copy link
Member

I tired to reproduce this using the ESLint extension but failed. Which version of the client library are you using?

@dbaeumer dbaeumer added the info-needed Issue requires more information from poster label Apr 26, 2018
@dbaeumer
Copy link
Member

I know there were issues when restarting the server (see issues here).

@nrc
Copy link
Author

nrc commented Apr 26, 2018

Which version of the client library are you using?

4.0.0

There is a PR to upgrade us to 4.1.0, so I'll investigate with that too.

@nrc
Copy link
Author

nrc commented Apr 26, 2018

I can still repro with 4.1.0

Is there any logging I can provide which would be useful?

@dbaeumer
Copy link
Member

You can try to debug this. The code that is invoked on connection close and does the restart is here:

https://github.com/Microsoft/vscode-languageserver-node/blob/master/client/src/client.ts#L2787

And the cleanup of the listeners happens here:

https://github.com/Microsoft/vscode-languageserver-node/blob/master/client/src/client.ts#L2704

Do these methods get executed when you kill the server?

@vscodebot vscodebot bot closed this as completed May 4, 2018
@vscodebot
Copy link

vscodebot bot commented May 4, 2018

This issue has been closed automatically because it needs more information and has not had recent activity. See also our issue reporting guidelines.

Happy Coding!

@dbaeumer
Copy link
Member

dbaeumer commented May 7, 2018

@nrc any information ?

@nrc
Copy link
Author

nrc commented May 10, 2018

@dbaeumer Hi, sorry I haven't had a chance to try and debug yet. Hopefully I'll give it a go tomorrow.

@nrc
Copy link
Author

nrc commented May 16, 2018

@dbaeumer Hi, sorry it is a bit later than expected, but I had a look and I have (I think) diagnosed what is going on.

The BaseLanguageClient has an array of _features. This array is initialised when the client is constructed, and never destroyed, it is not created/destroyed on start/stop like the connection.

When the client is started it calls initialize which calls initializeFeatures (https://github.com/Microsoft/vscode-languageserver-node/blob/master/client/src/client.ts#L2704). That in turn calls initialize, then register for each feature, which for DidChangeTextDocumentFeature creates an entry in the _changeData Map (https://github.com/Microsoft/vscode-languageserver-node/blob/master/client/src/client.ts#L2704).

Because the features are not reset as part of the start/stop lifecycle, the _changeData map is never reset, so after n restarts there will be n+1 entries in the map.

Now, when a change happens, the DidChangeTextDocumentFeature's callback method is called (once), but that loops over _changeData (https://github.com/Microsoft/vscode-languageserver-node/blob/master/client/src/client.ts#L2704) and so sends the notification multiple times when it should be sent once.

I believe the fix is to move the call to initializeFeatures from the BaseLanguageClient's initialize method to its constructor. However, perhaps features are added the end of the ctor (registerBuiltinFeatures) but before initializeFeatures is called, in which case an alternative fix would be to 'un-initialise' (i.e., empty _changeData) each feature in BaseLanguageClient::cleanup.

@dbaeumer
Copy link
Member

@nrc thanks a lot for the very good analysis. Very good catch.

I didn't see this with ESLint since it uses a full text sync and these are debounced on the client side hence they are only send once.

The fix is quite simple. Each feature has a dispose method which is called when the server goes down. The DidChangeTextDocumentFeature simply doesn't reset the map in dispose :-(.

@dbaeumer dbaeumer reopened this May 16, 2018
@dbaeumer dbaeumer added bug Issue identified by VS Code Team member as probable bug and removed info-needed Issue requires more information from poster labels May 16, 2018
@dbaeumer dbaeumer added this to the May 2018 milestone May 16, 2018
@dbaeumer
Copy link
Member

@nrc I published a new client and server. Please let me know if using these fixes the problem.

@nrc
Copy link
Author

nrc commented May 17, 2018

I updated and checked and it seems to be working fine now. Thanks for the fix!

@dbaeumer
Copy link
Member

@nrc and thanks again for the analysis.

@vscodebot vscodebot bot locked and limited conversation to collaborators Jun 30, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Issue identified by VS Code Team member as probable bug
Projects
None yet
Development

No branches or pull requests

2 participants