PT #166603176: Limit hover request processing time
This commit is contained in:
@@ -119,6 +119,8 @@ public abstract class STS4LanguageServerProcessStreamConnector extends ProcessSt
|
||||
|
||||
command.add(mainClass);
|
||||
|
||||
command.add("--languageserver.hover-timeout=225");
|
||||
|
||||
setCommands(command.build());
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
||||
@@ -34,6 +34,11 @@ public class LanguageServerProperties {
|
||||
* triggers.
|
||||
*/
|
||||
private Map<String, String> completionTriggerCharacters;
|
||||
|
||||
/**
|
||||
* Hover request handler timeout in milliseconds
|
||||
*/
|
||||
private long hoverTimeout = -1;
|
||||
|
||||
public boolean isStandalone() {
|
||||
return standalone;
|
||||
@@ -67,4 +72,12 @@ public class LanguageServerProperties {
|
||||
this.completionTriggerCharacters = completionTriggerCharacters;
|
||||
}
|
||||
|
||||
public long getHoverTimeout() {
|
||||
return hoverTimeout;
|
||||
}
|
||||
|
||||
public void setHoverTimeout(long hoverTimeout) {
|
||||
this.hoverTimeout = hoverTimeout;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ import org.springframework.ide.vscode.commons.languageserver.completion.IComplet
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter.CompletionFilter;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter.LazyCompletionResolver;
|
||||
import org.springframework.ide.vscode.commons.languageserver.config.LanguageServerProperties;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ls.ClasspathListener;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ls.ClasspathListenerManager;
|
||||
import org.springframework.ide.vscode.commons.languageserver.quickfix.Quickfix;
|
||||
@@ -114,6 +115,7 @@ public final class SimpleLanguageServer implements Sts4LanguageServer, LanguageC
|
||||
private SimpleTextDocumentService tds;
|
||||
private SimpleWorkspaceService workspace;
|
||||
private STS4LanguageClient client;
|
||||
private final LanguageServerProperties props;
|
||||
|
||||
private ProgressService progressService = (String taskId, String statusMsg) -> {
|
||||
STS4LanguageClient client = SimpleLanguageServer.this.client;
|
||||
@@ -187,8 +189,9 @@ public final class SimpleLanguageServer implements Sts4LanguageServer, LanguageC
|
||||
}
|
||||
}
|
||||
|
||||
public SimpleLanguageServer(String extensionId, ApplicationContext appContext) {
|
||||
public SimpleLanguageServer(String extensionId, ApplicationContext appContext, LanguageServerProperties props) {
|
||||
this.appContext = appContext;
|
||||
this.props = props;
|
||||
Assert.isNotNull(extensionId);
|
||||
this.EXTENSION_ID = extensionId;
|
||||
this.CODE_ACTION_COMMAND_ID = "sts."+EXTENSION_ID+".codeAction";
|
||||
@@ -485,7 +488,7 @@ public final class SimpleLanguageServer implements Sts4LanguageServer, LanguageC
|
||||
}
|
||||
|
||||
protected SimpleTextDocumentService createTextDocumentService() {
|
||||
return new SimpleTextDocumentService(this);
|
||||
return new SimpleTextDocumentService(this, props);
|
||||
}
|
||||
|
||||
public SimpleWorkspaceService createWorkspaceService() {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.commons.languageserver.util;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -59,6 +60,7 @@ import org.eclipse.lsp4j.services.LanguageClient;
|
||||
import org.eclipse.lsp4j.services.TextDocumentService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.commons.languageserver.config.LanguageServerProperties;
|
||||
import org.springframework.ide.vscode.commons.languageserver.quickfix.Quickfix;
|
||||
import org.springframework.ide.vscode.commons.util.Assert;
|
||||
import org.springframework.ide.vscode.commons.util.AsyncRunner;
|
||||
@@ -70,11 +72,14 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public class SimpleTextDocumentService implements TextDocumentService, DocumentEventListenerManager {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(SimpleTextDocumentService.class);
|
||||
|
||||
|
||||
final private SimpleLanguageServer server;
|
||||
final private LanguageServerProperties props;
|
||||
private Map<String, TrackedDocument> documents = new HashMap<>();
|
||||
private ListenerList<TextDocumentContentChange> documentChangeListeners = new ListenerList<>();
|
||||
private ListenerList<TextDocument> documentCloseListeners = new ListenerList<>();
|
||||
@@ -97,8 +102,9 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE
|
||||
private AsyncRunner async;
|
||||
|
||||
|
||||
public SimpleTextDocumentService(SimpleLanguageServer server) {
|
||||
public SimpleTextDocumentService(SimpleLanguageServer server, LanguageServerProperties props) {
|
||||
this.server = server;
|
||||
this.props = props;
|
||||
this.async = server.getAsync();
|
||||
}
|
||||
|
||||
@@ -324,19 +330,24 @@ public class SimpleTextDocumentService implements TextDocumentService, DocumentE
|
||||
@Override
|
||||
public CompletableFuture<Hover> hover(TextDocumentPositionParams position) {
|
||||
log.debug("hover requested for {}", position);
|
||||
return async.invoke(() -> {
|
||||
try {
|
||||
log.debug("hover handler starting");
|
||||
HoverHandler h = hoverHandler;
|
||||
if (h!=null) {
|
||||
return hoverHandler.handle(position);
|
||||
}
|
||||
log.debug("no hover because there is no handler");
|
||||
return null;
|
||||
} finally {
|
||||
log.debug("hover handler finished");
|
||||
long timeout = props.getHoverTimeout();
|
||||
return timeout <= 0 ? async.invoke(() -> computeHover(position)) : async.invoke(Duration.ofMillis(timeout), () -> computeHover(position), Mono.fromRunnable(() -> {
|
||||
log.error("Hover Request handler timed out after {} ms.", timeout);
|
||||
}));
|
||||
}
|
||||
|
||||
private Hover computeHover(TextDocumentPositionParams position) {
|
||||
try {
|
||||
log.debug("hover handler starting");
|
||||
HoverHandler h = hoverHandler;
|
||||
if (h!=null) {
|
||||
return hoverHandler.handle(position);
|
||||
}
|
||||
});
|
||||
log.debug("no hover because there is no handler");
|
||||
return null;
|
||||
} finally {
|
||||
log.debug("hover handler finished");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* Copyright (c) 2018, 2019 Pivotal, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
@@ -41,6 +41,15 @@ public class AsyncRunner {
|
||||
return x;
|
||||
}
|
||||
|
||||
public synchronized <T> CompletableFuture<T> invoke(Duration timeout, Callable<T> callable, Mono<T> fallback) {
|
||||
CompletableFuture<T> x = Mono.fromCallable(callable)
|
||||
.subscribeOn(executor)
|
||||
.timeout(timeout, fallback)
|
||||
.toFuture();
|
||||
lastRequest = x;
|
||||
return x;
|
||||
}
|
||||
|
||||
public synchronized <T> CompletableFuture<T> invoke(Callable<T> callable) {
|
||||
CompletableFuture<T> x = Mono.fromCallable(callable).subscribeOn(executor).toFuture();
|
||||
lastRequest = x;
|
||||
|
||||
@@ -49,7 +49,7 @@ public class LanguageServerAutoConf {
|
||||
Optional<CompletionFilter> completionFilter,
|
||||
ApplicationContext appContext
|
||||
) throws Exception {
|
||||
SimpleLanguageServer server = new SimpleLanguageServer(props.getExtensionId(), appContext);
|
||||
SimpleLanguageServer server = new SimpleLanguageServer(props.getExtensionId(), appContext, props);
|
||||
server.setCompletionFilter(completionFilter);
|
||||
severities.ifPresent(server::setDiagnosticSeverityProvider);
|
||||
return server;
|
||||
|
||||
@@ -15,6 +15,7 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.commons.languageserver.config.LanguageServerProperties;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
import org.springframework.ide.vscode.commons.util.text.IRegion;
|
||||
@@ -36,7 +37,7 @@ public class DocumentEditsTest {
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
SimpleLanguageServer server = new SimpleLanguageServer("dont-care", null);
|
||||
SimpleLanguageServer server = new SimpleLanguageServer("dont-care", null, new LanguageServerProperties());
|
||||
harness = new LanguageServerHarness(server, LanguageId.PLAINTEXT);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.springframework.ide.vscode.boot.xml.SpringXMLLanguageServerComponents
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.VscodeCompletionEngineAdapter;
|
||||
import org.springframework.ide.vscode.commons.languageserver.composable.CompositeLanguageServerComponents;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.HoverHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
@@ -61,12 +62,14 @@ public class BootLanguageServerInitializer implements InitializingBean {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(BootLanguageServerInitializer.class);
|
||||
|
||||
private static ProjectObserver.Listener reconcileOpenDocuments(SimpleLanguageServer s, CompositeLanguageServerComponents c) {
|
||||
private static ProjectObserver.Listener reconcileOpenDocuments(SimpleLanguageServer s, CompositeLanguageServerComponents c, JavaProjectFinder projectFinder) {
|
||||
return ProjectObserver.onAny(project -> {
|
||||
c.getReconcileEngine().ifPresent(reconciler -> {
|
||||
log.info("A project changed {}, triggering reconcile on all open documents", project.getElementName());
|
||||
log.info("A project changed {}, triggering reconcile on all project's open documents", project.getElementName());
|
||||
for (TextDocument doc : s.getTextDocumentService().getAll()) {
|
||||
s.validateWith(doc.getId(), reconciler);
|
||||
if (projectFinder.find(doc.getId()).orElse(null) == project) {
|
||||
s.validateWith(doc.getId(), reconciler);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -81,7 +84,7 @@ public class BootLanguageServerInitializer implements InitializingBean {
|
||||
builder.add(new BootJavaLanguageServerComponents(server, params, sourceLinks, cuCache, adHocProperties, symbolCache, config, springIndexer, runningAppProvider));
|
||||
builder.add(new SpringXMLLanguageServerComponents(server, springIndexer, params, config));
|
||||
components = builder.build(server);
|
||||
params.projectObserver.addListener(reconcileOpenDocuments(server, components));
|
||||
params.projectObserver.addListener(reconcileOpenDocuments(server, components, params.projectFinder));
|
||||
|
||||
SimpleTextDocumentService documents = server.getTextDocumentService();
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user