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

Added restart java language server command #2586

Merged
merged 1 commit into from
Apr 27, 2023

Conversation

AlexXuChen
Copy link

@AlexXuChen AlexXuChen commented Jul 21, 2022

Added Restart Java Language Server command, java.language.server.restart.
Screen Recording 2022-08-05 at 8 14 19 PM

Signed-off-by: Alexander Chen alchen@redhat.com

@AlexXuChen
Copy link
Author

It seems the standard server won't start back up when the server mode is HYBRID

@rgrunber
Copy link
Member

rgrunber commented Jul 21, 2022

It seems the standard server won't start back up when the server mode is HYBRID

What happens if in the "Hybrid" case, you use syntaxClient.isAlive() and only stop/start if true. Otherwise, just stop/start the standard client for now.

@AlexXuChen AlexXuChen force-pushed the restart-server-command branch 3 times, most recently from d5c99f6 to 4619154 Compare July 21, 2022 18:49
@rgrunber
Copy link
Member

rgrunber commented Jul 21, 2022

StandardLanguageClient.start() does nothing because the underlying languageClient is null. It's null because StandardLanguageClient.stop() sets it that way (look inside the declaration).

Originally stop() was only really called on extension deactivate() so setting everything null was probably fine. Now, we want to stop the client but still re-use the connection so I would add a parameter to the stop(), something like boolean cleanup. It would be called with false for the restart command and true in deactivate()

@AlexXuChen
Copy link
Author

Originally stop() was only really called on extension deactivate() so setting everything null was probably fine. Now, we want to stop the client but still re-use the connection so I would add a parameter to the stop(), something like boolean cleanup. It would be called with false for the restart command and true in deactivate()

Ah I see, because StandardLanguageClient.stop() is a wrapper for the LanguageClient.stop()

@AlexXuChen AlexXuChen force-pushed the restart-server-command branch 3 times, most recently from 48f9e66 to 5d41d75 Compare July 21, 2022 21:29
src/extension.ts Outdated
switch (getJavaServerMode()) {
case (ServerMode.STANDARD):
// Standard server restart
await standardClient.restart();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of using the wrapper start(), stop(), I instead created a restart for both the standardClient and syntaxClient. This way, the languageClient won't be set to null and the ClientStatus won't change.

@AlexXuChen AlexXuChen force-pushed the restart-server-command branch 4 times, most recently from 65ee0a9 to 56369b0 Compare July 26, 2022 13:34
@rgrunber
Copy link
Member

rgrunber commented Aug 2, 2022

@testforstephen , you mentioned there's already an issue, or PR for this that's incoming ? I wasn't able to find any issue on the vscode-java-debug end.

@testforstephen
Copy link
Collaborator

@testforstephen , you mentioned there's already an issue, or PR for this that's incoming ? I wasn't able to find any issue on the vscode-java-debug end.

@rgrunber I tried this PR and Java debugger works fine after a language server restart. The reason is that the current restart implementation does not trigger a server mode change event and has no effect on the debugger.

Previously we saw some side effects when restarting because that implementation would destroy the languageClient and recreate a new one, which would cause the Java extension to resend the server mode change event.

However, I found another issue that the status icon is always spinning after language server restart.
image

@rgrunber
Copy link
Member

rgrunber commented Aug 3, 2022

I think I saw this as well initially. Our own wrappers destroy the entire client, but we don't need to do that, so I believe @AlexXuChen just made a separate method that just calls the necessary API on the LanguageClient.

Yes, I saw the spinning build status provider as well, and hopefully it can be fixed. As the startup process receives a lot of notifications and state changes, perhaps something isn't set correctly or expecting to go through an earlier phase again.

@testforstephen , if there's no PR planned (or other draft) on your end to address this, I think Alex should continue improving this, as it would be nice to have such a restart capability.

@AlexXuChen AlexXuChen force-pushed the restart-server-command branch 2 times, most recently from 6bc6704 to cf9f568 Compare August 5, 2022 22:50
@datho7561
Copy link
Contributor

I just tried this PR with vscode-microprofile, which provides a eclipse.jdt.ls extension and a language server that communicates with the eclipse.jdt.ls extension using language server commands. Restarting works very well; as soon as the server restarts, all the microprofile features start working again. The only issue I ran into while doing this is that the microprofile language server sends sends error notifications while eclipse.jdt.ls is down. This makes sense, since the microprofile language server is trying to make requests to eclipse.jdt.ls while it's not running. However, it might confuse the end user, since they might think something is wrong. It would be nice to prevent these errors from appearing, perhaps with an API to detect if the server is restarting, but I think that could wait to a future PR.

@AlexXuChen AlexXuChen marked this pull request as ready for review August 8, 2022 13:13
@testforstephen
Copy link
Collaborator

The message id doesn't exist in package.nls.json.
image

let me know if this works for you now. I think the last thing to test is specifically how it interacts when one is using vscode-java-debug or anything else.

Tried again with the latest commit and if there is a debug session running, the restart operation will terminate the debugger. Once the server is ready, the debugging feature works again. It doesn't break the Java debugger, which is good for me.

Just one concern is about the transparency of the operation. When I execute "Restart Java Language Server", there is currently no indicator to tell me what is happening in the background and when the server will be ready again. I'm wondering whether it's better to show a progress notification on restart opreation.

@rgrunber
Copy link
Member

rgrunber commented Aug 17, 2022

The only other issue I see is that in syntax client mode ("java.server.launchMode": "LightWeight"), I get a popup indicating the command to restart resulted in an error, "Connection is disposed". The server does not restart. If I call the same command while the language server is down, it does start back up.

Update : This appears to be #2366

Just one concern is about the transparency of the operation. When I execute "Restart Java Language Server", there is currently no indicator to tell me what is happening in the background and when the server will be ready again. I'm wondering whether it's better to show a progress notification on restart opreation.

This could probably be done with window.withProgress(..), (which we use in a few places). It would at least indicate how long the restart operation takes but to have the progress disappear exactly when the server is back up (rather when the restart operation finishes) might be tricky. Maybe listening for any notification after the restart would be indication it has returned and then disposing of that onNotification listener might work.

@rgrunber rgrunber self-assigned this Aug 31, 2022
@rgrunber
Copy link
Member

In the process of trying to make the progress notification disappear once the server is responding again (as opposed to once the restart command has finished being issued), I've discovered that once the language server is restarted, it fails to receive notifications on any of the onNotification(...) callbacks. That's... not good.

Although this is a deal breaker, it's actually microsoft/vscode-languageserver-node#770, which was fixed in 8.0. So we now depend on #2474 in order to merge this change. Hopefully we'll be able to do that pretty soon.

@JessicaJHee
Copy link
Contributor

As a side note, I run into the following problem while in debug mode sometimes:

ERROR: transport error 202: bind failed: Address already in use
ERROR: JDWP Transport dt_socket failed to initialize, TRANSPORT_INIT(510)
JDWP exit error AGENT_ERROR_TRANSPORT_INIT(197): No transports initialized [../src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c:734]

The problem is solved with the timeout set to 2000 instead of 1000 here:
https://github.com/microsoft/vscode-languageserver-node/blob/ffaf05ddd1fa9ca5f258cd0b08cc6cd1794c5b57/client/src/node/main.ts#L197

@rgrunber
Copy link
Member

rgrunber commented Apr 26, 2023

In the previous iteration of this PR, we had it set at 2000 (I suspect I saw issues with 1000). However now it's handled by the library so we don't really have control. It's mainly an annoying problem for developers because in production those debug ports aren't open (so no cases of LS shutdown still bound to 1044 while new one starting attempts to bind to 1044) though.

Worst case, we could just do what we did before. Copy the restart() logic and do it ourselves (replacing 1000 -> 2000). I'll try and see how bad it is.

@rgrunber rgrunber added this to the End May 2023 milestone Apr 27, 2023
@rgrunber
Copy link
Member

rgrunber commented Apr 27, 2023

This works really well for me with the eclipse.jdt.ls modification to the Shutdown job. I've tried restarting with various launch modes. I noticed that if no server is running (eg. invisible project with no files opened, or empty workspace), one can still restart the language server (though it never started once to begin with). It doesn't appear harmful. Still seems to succeed although maybe we shouldn't allow this to happen. Have a look at the "when": "javaLSReady" context for commands in the palette and let me know if that makes sense for such cases.

Copy link
Member

@rgrunber rgrunber left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would just add your info as a Co-authored-by: in the commit body (at the bottom) and I think we can merge.

- Show progress for restarting the language server

Signed-off-by: AlexXuChen <alex.xu.chen@gmail.com>
Co-authored-by: Roland Grunberg <rgrunber@redhat.com>
Co-authored-by: Jessica He <jhe@redhat.com>
@rgrunber rgrunber merged commit bd03b35 into redhat-developer:master Apr 27, 2023
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

None yet

6 participants