Fix for long hang on reconcile
This commit is contained in:
@@ -40,6 +40,10 @@ import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.Futures;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.scheduler.Scheduler;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
|
||||
/**
|
||||
* Abstract base class to implement LanguageServer. Bits and pieces copied from
|
||||
* the 'JavaLanguageServer' example which seem generally useful / reusable end up in
|
||||
@@ -50,6 +54,8 @@ public abstract class SimpleLanguageServer implements LanguageServer, LanguageCl
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(SimpleLanguageServer.class.getName());
|
||||
|
||||
private static final Scheduler RECONCILER_SCHEDULER = Schedulers.newSingle("Reconciler");
|
||||
|
||||
private Path workspaceRoot;
|
||||
|
||||
private SimpleTextDocumentService tds;
|
||||
@@ -65,6 +71,8 @@ public abstract class SimpleLanguageServer implements LanguageServer, LanguageCl
|
||||
}
|
||||
};
|
||||
|
||||
private CompletableFuture<Void> busyReconcile = CompletableFuture.completedFuture(null);
|
||||
|
||||
@Override
|
||||
public void connect(LanguageClient _client) {
|
||||
this.client = (STS4LanguageClient) _client;
|
||||
@@ -150,7 +158,10 @@ public abstract class SimpleLanguageServer implements LanguageServer, LanguageCl
|
||||
* Convenience method. Subclasses can call this to use a {@link IReconcileEngine} ported
|
||||
* from old STS codebase to validate a given {@link TextDocument} and publish Diagnostics.
|
||||
*/
|
||||
protected void validateWith(TextDocument doc, IReconcileEngine engine) {
|
||||
protected void validateWith(TextDocument _doc, IReconcileEngine engine) {
|
||||
TextDocument doc = _doc.copy();
|
||||
|
||||
this.busyReconcile = new CompletableFuture<Void>();
|
||||
|
||||
SimpleTextDocumentService documents = getTextDocumentService();
|
||||
IProblemCollector problems = new IProblemCollector() {
|
||||
@@ -198,7 +209,23 @@ public abstract class SimpleLanguageServer implements LanguageServer, LanguageCl
|
||||
}
|
||||
}
|
||||
};
|
||||
engine.reconcile(doc, problems);
|
||||
|
||||
// Avoid running in the same thread as lsp4j as it can result
|
||||
// in long "hangs" for slow reconcile providers
|
||||
Mono.fromRunnable(() -> {
|
||||
engine.reconcile(doc, problems);
|
||||
})
|
||||
.doOnTerminate((ignore1, ignore2) -> {
|
||||
busyReconcile.complete(null);
|
||||
})
|
||||
.subscribeOn(RECONCILER_SCHEDULER)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
public void waitForReconcile() throws Exception {
|
||||
while (!this.busyReconcile.isDone()) {
|
||||
this.busyReconcile.get();
|
||||
}
|
||||
}
|
||||
|
||||
public LanguageClient getClient() {
|
||||
|
||||
@@ -221,7 +221,7 @@ public class Editor {
|
||||
: "";
|
||||
}
|
||||
|
||||
private List<Diagnostic> reconcile() {
|
||||
private List<Diagnostic> reconcile() throws Exception {
|
||||
// We assume the language server works synchronously for now and it does an immediate reconcile
|
||||
// when the document changes. In the future this is probably not going to be the case though and then this
|
||||
// method will need to somehow ensure the linter is done working before retrieving the problems from the
|
||||
|
||||
@@ -54,6 +54,7 @@ import org.eclipse.lsp4j.services.LanguageServer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.LanguageIds;
|
||||
import org.springframework.ide.vscode.commons.languageserver.ProgressParams;
|
||||
import org.springframework.ide.vscode.commons.languageserver.STS4LanguageClient;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
|
||||
public class LanguageServerHarness {
|
||||
|
||||
@@ -61,10 +62,10 @@ public class LanguageServerHarness {
|
||||
|
||||
private Random random = new Random();
|
||||
|
||||
private Callable<? extends LanguageServer> factory;
|
||||
private Callable<? extends SimpleLanguageServer> factory;
|
||||
private String defaultLanguageId;
|
||||
|
||||
private LanguageServer server;
|
||||
private SimpleLanguageServer server;
|
||||
|
||||
private InitializeResult initResult;
|
||||
|
||||
@@ -72,12 +73,12 @@ public class LanguageServerHarness {
|
||||
private Map<String, PublishDiagnosticsParams> diagnostics = new HashMap<>();
|
||||
|
||||
|
||||
public LanguageServerHarness(Callable<? extends LanguageServer> factory, String defaultLanguageId) {
|
||||
public LanguageServerHarness(Callable<? extends SimpleLanguageServer> factory, String defaultLanguageId) {
|
||||
this.factory = factory;
|
||||
this.defaultLanguageId = defaultLanguageId;
|
||||
}
|
||||
|
||||
public LanguageServerHarness(Callable<? extends LanguageServer> factory) throws Exception {
|
||||
public LanguageServerHarness(Callable<? extends SimpleLanguageServer> factory) throws Exception {
|
||||
this(factory, LanguageIds.PLAINTEXT);
|
||||
}
|
||||
|
||||
@@ -263,7 +264,8 @@ public class LanguageServerHarness {
|
||||
return TextDocumentSyncKind.None;
|
||||
}
|
||||
|
||||
public PublishDiagnosticsParams getDiagnostics(TextDocumentInfo doc) {
|
||||
public PublishDiagnosticsParams getDiagnostics(TextDocumentInfo doc) throws Exception {
|
||||
this.server.waitForReconcile();
|
||||
return diagnostics.get(doc.getUri());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user