@@ -318,8 +318,14 @@ public synchronized void start() throws LanguageServerException {
318318 final VirtualFile rootURI = getRootURI ();
319319 this .launcherFuture = new CompletableFuture <>();
320320 var context = this .currentInitializingContext = new InitializingContext ();
321- this .initializeFuture = CompletableFuture .supplyAsync (() -> {
322-
321+ // Use IntelliJ pooled thread instead of ForkJoinPool.commonPool() to avoid
322+ // ForkJoinPool.helpAsyncBlocker() executing blocking operations (like OSProcessHandler.waitFor())
323+ // in the current thread when called from ReadAction.
324+ // We cannot use 'dispatcher' (single thread executor) as it's reserved for ordered notification dispatch.
325+ // See: https://github.com/redhat-developer/lsp4ij/issues/1442
326+ CompletableFuture <InitializingContext > startFuture = new CompletableFuture <>();
327+ ApplicationManager .getApplication ().executeOnPooledThread (() -> {
328+ try {
323329 var initializingContext = context ;
324330 // Starting process...
325331 updateStatus (ServerStatus .starting );
@@ -362,8 +368,13 @@ public synchronized void start() throws LanguageServerException {
362368 // Throws the CannotStartProcessException exception if process is not alive.
363369 // This use case comes for instance when the start process command fails (not a valid start command)
364370 provider .ensureIsAlive ();
365- return currentInitializingContext ;
366- }).thenApply (initializingContext -> {
371+ startFuture .complete (currentInitializingContext );
372+ } catch (Exception e ) {
373+ startFuture .completeExceptionally (e );
374+ }
375+ });
376+ this .initializeFuture = startFuture
377+ .thenApply (initializingContext -> {
367378 var languageClient = serverDefinition .createLanguageClient (initialProject );
368379 initializingContext .languageClient = languageClient ;
369380 languageClient .setServerWrapper (this );
0 commit comments