Skip to content

Commit e72c7a4

Browse files
committed
avoid blocking suggest contract calls from main server loop
1 parent ed1447b commit e72c7a4

File tree

2 files changed

+28
-18
lines changed

2 files changed

+28
-18
lines changed

apps/language_server/lib/language_server/dialyzer.ex

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,13 @@ defmodule ElixirLS.LanguageServer.Dialyzer do
7676
)
7777
end
7878

79-
def suggest_contracts(server \\ {:global, {self(), __MODULE__}}, files)
79+
def suggest_contracts(parent \\ self(), files)
8080

81-
def suggest_contracts(_server, []), do: []
81+
def suggest_contracts(_parent, []), do: []
8282

83-
def suggest_contracts(server, files) do
83+
def suggest_contracts(parent, files) do
8484
try do
85-
GenServer.call(server, {:suggest_contracts, files}, :infinity)
85+
GenServer.call({:global, {parent, __MODULE__}}, {:suggest_contracts, files}, :infinity)
8686
catch
8787
kind, payload ->
8888
{payload, stacktrace} = Exception.blame(kind, payload, __STACKTRACE__)

apps/language_server/lib/language_server/server.ex

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,12 @@ defmodule ElixirLS.LanguageServer.Server do
249249
case state do
250250
%{analysis_ready?: true, source_files: %{^uri => %{dirty?: false}}} ->
251251
abs_path = SourceFile.Path.absolute_from_uri(uri, state.project_dir)
252-
{:reply, Dialyzer.suggest_contracts([abs_path]), state}
252+
parent = self()
253+
spawn(fn ->
254+
contracts = Dialyzer.suggest_contracts(parent, [abs_path])
255+
GenServer.reply(from, contracts)
256+
end)
257+
{:noreply, state}
253258

254259
%{source_files: %{^uri => _}} ->
255260
# file not saved or analysis not finished
@@ -1521,19 +1526,24 @@ defmodule ElixirLS.LanguageServer.Server do
15211526
Map.fetch!(state.source_files, uri).dirty?
15221527
end)
15231528

1524-
contracts_by_file =
1525-
not_dirty
1526-
|> Enum.map(fn {_from, uri} -> SourceFile.Path.from_uri(uri) end)
1527-
|> Dialyzer.suggest_contracts()
1528-
|> Enum.group_by(fn {file, _, _, _, _} -> file end)
1529-
1530-
for {from, uri} <- not_dirty do
1531-
contracts =
1532-
contracts_by_file
1533-
|> Map.get(SourceFile.Path.from_uri(uri), [])
1534-
1535-
GenServer.reply(from, contracts)
1536-
end
1529+
# Dialyzer.suggest_contracts is blocking and can take a long time to complete
1530+
# if we block here we hang the server
1531+
parent = self()
1532+
spawn(fn ->
1533+
contracts_by_file =
1534+
not_dirty
1535+
|> Enum.map(fn {_from, uri} -> SourceFile.Path.from_uri(uri) end)
1536+
|> then(fn uris -> Dialyzer.suggest_contracts(parent, uris) end)
1537+
|> Enum.group_by(fn {file, _, _, _, _} -> file end)
1538+
1539+
for {from, uri} <- not_dirty do
1540+
contracts =
1541+
contracts_by_file
1542+
|> Map.get(SourceFile.Path.from_uri(uri), [])
1543+
1544+
GenServer.reply(from, contracts)
1545+
end
1546+
end)
15371547

15381548
%{state | analysis_ready?: true, awaiting_contracts: dirty}
15391549
else

0 commit comments

Comments
 (0)